This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git


The following commit(s) were added to refs/heads/main by this push:
     new f61d7c94b Add protobuf based MetadataService support (#2723)
f61d7c94b is described below

commit f61d7c94bfd21200ba808f7b9f7f40772ee92b35
Author: Ken Liu <[email protected]>
AuthorDate: Thu Aug 8 12:49:12 2024 +0800

    Add protobuf based MetadataService support (#2723)
---
 Makefile                                           |   2 +-
 client/compat.go                                   |  20 +-
 client/options.go                                  |   8 +-
 cluster/router/affinity/router_test.go             |  10 +-
 cluster/router/script/router_test.go               |  10 +-
 common/constant/default.go                         |   1 +
 common/constant/key.go                             |  19 +-
 common/extension/metadata_service_exporter.go      |   6 +-
 .../extension/metadata_service_proxy_factory_v2.go |  50 +++
 ..._service_exporter.go => metadata_service_v1.go} |  31 +-
 ..._service_exporter.go => metadata_service_v2.go} |  31 +-
 common/host_util.go                                |  12 +
 compat.go                                          |  20 +-
 config/application_config.go                       |  21 +-
 config/root_config.go                              |  31 +-
 config/service_config.go                           |  18 +-
 global/application_config.go                       |  26 +-
 metadata/metadata.go                               |  48 ++-
 metadata/service/exporter/configurable/exporter.go | 162 +++++++--
 .../service/exporter/configurable/exporter_test.go |  13 +-
 metadata/service/exporter/exporter.go              |   2 +-
 .../local/metadata_service_proxy_factory.go        |  50 ++-
 metadata/service/local/service.go                  |  92 +++++
 metadata/service/local/service_proxy.go            |  89 ++++-
 metadata/service/local_service.go                  |  32 ++
 .../proto/hessian2_extend/hessian2_extend.proto    |  59 +++
 .../proto/java8_time/java8_time.proto}             |  44 ++-
 .../proto/java_exception/java_exception.proto      | 196 ++++++++++
 .../proto/java_math/java_math.proto}               |  18 +-
 .../proto/java_sql_time/java_sql_time.proto}       |  18 +-
 .../proto/java_util/java_util.proto}               |  20 +-
 .../triple_api/proto/metadata_service.hessian2.go  | 127 +++++++
 metadata/triple_api/proto/metadata_service.proto   |  72 ++++
 .../triple_api/proto/metadata_service_v2.pb.go     | 402 +++++++++++++++++++++
 .../proto/metadata_service_v2.proto}               |  37 +-
 .../proto/self_extension/self_extension.proto      |  15 +
 options.go                                         |  16 +
 protocol/triple/triple.go                          |  17 +
 protocol/triple/triple_protocol/envelope.go        |   4 +-
 .../event/metadata_service_version_customizer.go   |  34 +-
 registry/exposed_tmp/exposed.go                    |   7 +
 .../servicediscovery/service_discovery_registry.go |   2 +-
 .../service_instances_changed_listener_impl.go     |  66 +++-
 server/action.go                                   |  10 -
 server/compat.go                                   |  20 +-
 server/metadata.go                                 |  93 +++++
 server/server.go                                   |  14 +-
 47 files changed, 1820 insertions(+), 275 deletions(-)

diff --git a/Makefile b/Makefile
index e322a004e..caa2546bb 100644
--- a/Makefile
+++ b/Makefile
@@ -63,7 +63,7 @@ deps: prepare
 
 .PHONY: license
 license: clean prepareLic
-       $(GO_LICENSE_CHECKER) -v -a -r -i 
vendor,protocol/triple/triple_protocol,protocol/triple/reflection,cmd/protoc-gen-go-triple/internal
 $(LICENSE_DIR)/license.txt . go && [[ -z `git status -s` ]]
+       $(GO_LICENSE_CHECKER) -v -a -r -i 
vendor,protocol/triple/triple_protocol,protocol/triple/reflection,metadata/triple_api/proto
 $(LICENSE_DIR)/license.txt . go && [[ -z `git status -s` ]]
 
 .PHONY: verify
 verify: clean license test
diff --git a/client/compat.go b/client/compat.go
index b1f8d3895..3a91c9725 100644
--- a/client/compat.go
+++ b/client/compat.go
@@ -27,15 +27,17 @@ import (
 // todo(DMwangnima): remove these functions when refactoring dubbo-go
 func compatApplicationConfig(c *global.ApplicationConfig) 
*config.ApplicationConfig {
        return &config.ApplicationConfig{
-               Organization: c.Organization,
-               Name:         c.Name,
-               Module:       c.Module,
-               Group:        c.Group,
-               Version:      c.Version,
-               Owner:        c.Owner,
-               Environment:  c.Environment,
-               MetadataType: c.MetadataType,
-               Tag:          c.Tag,
+               Organization:            c.Organization,
+               Name:                    c.Name,
+               Module:                  c.Module,
+               Group:                   c.Group,
+               Version:                 c.Version,
+               Owner:                   c.Owner,
+               Environment:             c.Environment,
+               MetadataType:            c.MetadataType,
+               Tag:                     c.Tag,
+               MetadataServicePort:     c.MetadataServicePort,
+               MetadataServiceProtocol: c.MetadataServiceProtocol,
        }
 }
 
diff --git a/client/options.go b/client/options.go
index 57487c725..ccb81f0df 100644
--- a/client/options.go
+++ b/client/options.go
@@ -124,7 +124,7 @@ func (refOpts *ReferenceOptions) init(opts 
...ReferenceOption) error {
 
        // init protocol
        if ref.Protocol == "" {
-               ref.Protocol = "tri"
+               ref.Protocol = constant.TriProtocol
                if refOpts.Consumer != nil && refOpts.Consumer.Protocol != "" {
                        ref.Protocol = refOpts.Consumer.Protocol
                }
@@ -342,7 +342,7 @@ func WithProtocolDubbo() ReferenceOption {
 
 func WithProtocolTriple() ReferenceOption {
        return func(opts *ReferenceOptions) {
-               opts.Reference.Protocol = "tri"
+               opts.Reference.Protocol = constant.TriProtocol
        }
 }
 
@@ -514,7 +514,7 @@ func (cliOpts *ClientOptions) init(opts ...ClientOption) 
error {
 
        // init protocol
        if cliOpts.Consumer.Protocol == "" {
-               cliOpts.Consumer.Protocol = "tri"
+               cliOpts.Consumer.Protocol = constant.TriProtocol
        }
 
        // init serialization
@@ -766,7 +766,7 @@ func WithClientProtocolDubbo() ClientOption {
 
 func WithClientProtocolTriple() ClientOption {
        return func(opts *ClientOptions) {
-               opts.Consumer.Protocol = "tri"
+               opts.Consumer.Protocol = constant.TriProtocol
        }
 }
 
diff --git a/cluster/router/affinity/router_test.go 
b/cluster/router/affinity/router_test.go
index ced11b6e7..d2f53fe6f 100644
--- a/cluster/router/affinity/router_test.go
+++ b/cluster/router/affinity/router_test.go
@@ -17,6 +17,14 @@
 
 package affinity
 
+import (
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
 import (
        "dubbo.apache.org/dubbo-go/v3/cluster/router/condition"
        "dubbo.apache.org/dubbo-go/v3/common"
@@ -24,8 +32,6 @@ import (
        "dubbo.apache.org/dubbo-go/v3/protocol"
        "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
        "dubbo.apache.org/dubbo-go/v3/remoting"
-       "github.com/stretchr/testify/assert"
-       "testing"
 )
 
 var providerUrls = []string{
diff --git a/cluster/router/script/router_test.go 
b/cluster/router/script/router_test.go
index bf3ff7551..a7fcb4d8b 100644
--- a/cluster/router/script/router_test.go
+++ b/cluster/router/script/router_test.go
@@ -19,13 +19,19 @@ package script
 
 import (
        "context"
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+import (
        "dubbo.apache.org/dubbo-go/v3/common"
        "dubbo.apache.org/dubbo-go/v3/config_center"
        "dubbo.apache.org/dubbo-go/v3/protocol"
        "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
        "dubbo.apache.org/dubbo-go/v3/remoting"
-       "github.com/stretchr/testify/assert"
-       "testing"
 )
 
 var url1 = func() *common.URL {
diff --git a/common/constant/default.go b/common/constant/default.go
index a27da2f4d..1abae1d02 100644
--- a/common/constant/default.go
+++ b/common/constant/default.go
@@ -27,6 +27,7 @@ const (
        OverrideProtocol = "override" //compatible with 2.6.x
        EmptyProtocol    = "empty"
        RouterProtocol   = "router"
+       TriProtocol      = "tri"
 )
 
 const (
diff --git a/common/constant/key.go b/common/constant/key.go
index 393036b38..7164b1250 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -353,12 +353,19 @@ const (
 // metadata report
 
 const (
-       MetaConfigRemote    = "remote"
-       MetaConfigLocal     = "local"
-       KeySeparator        = ":"
-       DefaultPathTag      = "metadata"
-       KeyRevisionPrefix   = "revision"
-       MetadataServiceName = "org.apache.dubbo.metadata.MetadataService" // 
metadata service
+       MetaConfigRemote      = "remote"
+       MetaConfigLocal       = "local"
+       KeySeparator          = ":"
+       DefaultPathTag        = "metadata"
+       KeyRevisionPrefix     = "revision"
+       MetadataServiceName   = "org.apache.dubbo.metadata.MetadataService"   
// metadata service
+       MetadataServiceV2Name = "org.apache.dubbo.metadata.MetadataServiceV2" 
// metadata service
+
+       MetadataVersion = "meta-v"
+
+       MetadataServiceV1        = "MetadataServiceV1"
+       MetadataServiceV2        = "MetadataServiceV2"
+       MetadataServiceV2Version = "2.0.0"
 )
 
 // service discovery
diff --git a/common/extension/metadata_service_exporter.go 
b/common/extension/metadata_service_exporter.go
index ab8cff8f4..1aea8762d 100644
--- a/common/extension/metadata_service_exporter.go
+++ b/common/extension/metadata_service_exporter.go
@@ -23,7 +23,7 @@ import (
        "dubbo.apache.org/dubbo-go/v3/metadata/service/exporter"
 )
 
-type MetadataServiceExporterCreator func(service.MetadataService) 
exporter.MetadataServiceExporter
+type MetadataServiceExporterCreator func(service.MetadataService, 
service.MetadataServiceV1, service.MetadataServiceV2) 
exporter.MetadataServiceExporter
 
 var (
        metadataServiceExporterInsMap = 
make(map[string]MetadataServiceExporterCreator, 2)
@@ -35,12 +35,12 @@ func SetMetadataServiceExporter(key string, creator 
MetadataServiceExporterCreat
 }
 
 // GetMetadataServiceExporter will create a MetadataServiceExporter instance
-func GetMetadataServiceExporter(key string, s service.MetadataService) 
exporter.MetadataServiceExporter {
+func GetMetadataServiceExporter(key string, s service.MetadataService, sV1 
service.MetadataServiceV1, sV2 service.MetadataServiceV2) 
exporter.MetadataServiceExporter {
        if key == "" {
                key = constant.DefaultKey
        }
        if creator, ok := metadataServiceExporterInsMap[key]; ok {
-               return creator(s)
+               return creator(s, sV1, sV2)
        }
        return nil
 }
diff --git a/common/extension/metadata_service_proxy_factory_v2.go 
b/common/extension/metadata_service_proxy_factory_v2.go
new file mode 100644
index 000000000..b3893f39a
--- /dev/null
+++ b/common/extension/metadata_service_proxy_factory_v2.go
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package extension
+
+import (
+       "fmt"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/metadata/service"
+)
+
+var metadataServiceProxyFactoryMapV2 = make(map[string]func() 
service.MetadataServiceProxyFactoryV2, 2)
+
+type MetadataServiceProxyFactoryFuncV2 func() 
service.MetadataServiceProxyFactoryV2
+
+// SetMetadataServiceProxyFactory store the name-creator pair
+func SetMetadataServiceProxyFactoryV2(name string, creator 
MetadataServiceProxyFactoryFuncV2) {
+       metadataServiceProxyFactoryMapV2[name] = creator
+}
+
+// GetMetadataServiceProxyFactory will create an instance.
+// it will panic if the factory with name not found
+func GetMetadataServiceProxyFactoryV2(name string) 
service.MetadataServiceProxyFactoryV2 {
+       if name == "" {
+               name = constant.DefaultKey
+       }
+       if f, ok := metadataServiceProxyFactoryMapV2[name]; ok {
+               return f()
+       }
+       panic(fmt.Sprintf("could not find the metadata service factory creator 
for name: %s, "+
+               "please check whether you have imported relative packages, "+
+               "local - dubbo.apache.org/dubbo-go/v3/metadata/service/local", 
name))
+}
diff --git a/common/extension/metadata_service_exporter.go 
b/common/extension/metadata_service_v1.go
similarity index 52%
copy from common/extension/metadata_service_exporter.go
copy to common/extension/metadata_service_v1.go
index ab8cff8f4..431480773 100644
--- a/common/extension/metadata_service_exporter.go
+++ b/common/extension/metadata_service_v1.go
@@ -17,30 +17,39 @@
 
 package extension
 
+import (
+       "fmt"
+)
+
+import (
+       perrors "github.com/pkg/errors"
+)
+
 import (
        "dubbo.apache.org/dubbo-go/v3/common/constant"
        "dubbo.apache.org/dubbo-go/v3/metadata/service"
-       "dubbo.apache.org/dubbo-go/v3/metadata/service/exporter"
 )
 
-type MetadataServiceExporterCreator func(service.MetadataService) 
exporter.MetadataServiceExporter
+type localMetadataServiceCreatorV1 func() (service.MetadataServiceV1, error)
 
 var (
-       metadataServiceExporterInsMap = 
make(map[string]MetadataServiceExporterCreator, 2)
+       localMetadataServiceInsMapV1 = 
make(map[string]localMetadataServiceCreatorV1, 2)
 )
 
-// SetMetadataServiceExporter will store the type => creator pair
-func SetMetadataServiceExporter(key string, creator 
MetadataServiceExporterCreator) {
-       metadataServiceExporterInsMap[key] = creator
+// SetLocalMetadataService will store the msType => creator pair
+func SetLocalMetadataServiceV1(key string, creator 
localMetadataServiceCreatorV1) {
+       localMetadataServiceInsMapV1[key] = creator
 }
 
-// GetMetadataServiceExporter will create a MetadataServiceExporter instance
-func GetMetadataServiceExporter(key string, s service.MetadataService) 
exporter.MetadataServiceExporter {
+// GetLocalMetadataService will create a local MetadataService instance
+func GetLocalMetadataServiceV1(key string) (service.MetadataServiceV1, error) {
        if key == "" {
                key = constant.DefaultKey
        }
-       if creator, ok := metadataServiceExporterInsMap[key]; ok {
-               return creator(s)
+       if creator, ok := localMetadataServiceInsMapV1[key]; ok {
+               return creator()
        }
-       return nil
+       return nil, perrors.New(fmt.Sprintf("could not find the metadata 
service creator for metadataType: local, " +
+               "please check whether you have imported relative packages, " +
+               "local - dubbo.apache.org/dubbo-go/v3/metadata/service/local"))
 }
diff --git a/common/extension/metadata_service_exporter.go 
b/common/extension/metadata_service_v2.go
similarity index 52%
copy from common/extension/metadata_service_exporter.go
copy to common/extension/metadata_service_v2.go
index ab8cff8f4..fe654ff27 100644
--- a/common/extension/metadata_service_exporter.go
+++ b/common/extension/metadata_service_v2.go
@@ -17,30 +17,39 @@
 
 package extension
 
+import (
+       "fmt"
+)
+
+import (
+       perrors "github.com/pkg/errors"
+)
+
 import (
        "dubbo.apache.org/dubbo-go/v3/common/constant"
        "dubbo.apache.org/dubbo-go/v3/metadata/service"
-       "dubbo.apache.org/dubbo-go/v3/metadata/service/exporter"
 )
 
-type MetadataServiceExporterCreator func(service.MetadataService) 
exporter.MetadataServiceExporter
+type localMetadataServiceCreatorV2 func() (service.MetadataServiceV2, error)
 
 var (
-       metadataServiceExporterInsMap = 
make(map[string]MetadataServiceExporterCreator, 2)
+       localMetadataServiceInsMapV2 = 
make(map[string]localMetadataServiceCreatorV2, 2)
 )
 
-// SetMetadataServiceExporter will store the type => creator pair
-func SetMetadataServiceExporter(key string, creator 
MetadataServiceExporterCreator) {
-       metadataServiceExporterInsMap[key] = creator
+// SetLocalMetadataService will store the msType => creator pair
+func SetLocalMetadataServiceV2(key string, creator 
localMetadataServiceCreatorV2) {
+       localMetadataServiceInsMapV2[key] = creator
 }
 
-// GetMetadataServiceExporter will create a MetadataServiceExporter instance
-func GetMetadataServiceExporter(key string, s service.MetadataService) 
exporter.MetadataServiceExporter {
+// GetLocalMetadataService will create a local MetadataService instance
+func GetLocalMetadataServiceV2(key string) (service.MetadataServiceV2, error) {
        if key == "" {
                key = constant.DefaultKey
        }
-       if creator, ok := metadataServiceExporterInsMap[key]; ok {
-               return creator(s)
+       if creator, ok := localMetadataServiceInsMapV2[key]; ok {
+               return creator()
        }
-       return nil
+       return nil, perrors.New(fmt.Sprintf("could not find the metadata 
service creator for metadataType: local, " +
+               "please check whether you have imported relative packages, " +
+               "local - dubbo.apache.org/dubbo-go/v3/metadata/service/local"))
 }
diff --git a/common/host_util.go b/common/host_util.go
index a1bbc4fa8..de42c7995 100644
--- a/common/host_util.go
+++ b/common/host_util.go
@@ -18,6 +18,7 @@
 package common
 
 import (
+       "fmt"
        "os"
        "strconv"
        "strings"
@@ -26,6 +27,8 @@ import (
 import (
        "github.com/dubbogo/gost/log/logger"
        gxnet "github.com/dubbogo/gost/net"
+
+       perrors "github.com/pkg/errors"
 )
 
 import (
@@ -106,3 +109,12 @@ func IsMatchGlobPattern(pattern, value string) bool {
                return strings.HasPrefix(value, prefix) && 
strings.HasSuffix(value, suffix)
        }
 }
+
+func GetRandomPort(ip string) string {
+       tcp, err := gxnet.ListenOnTCPRandomPort(ip)
+       if err != nil {
+               panic(perrors.New(fmt.Sprintf("Get tcp port error, err is 
{%v}", err)))
+       }
+       defer tcp.Close()
+       return strings.Split(tcp.Addr().String(), ":")[1]
+}
diff --git a/compat.go b/compat.go
index 3bede0b35..609aa3958 100644
--- a/compat.go
+++ b/compat.go
@@ -65,15 +65,17 @@ func compatApplicationConfig(c *global.ApplicationConfig) 
*config.ApplicationCon
                return nil
        }
        return &config.ApplicationConfig{
-               Organization: c.Organization,
-               Name:         c.Name,
-               Module:       c.Module,
-               Group:        c.Group,
-               Version:      c.Version,
-               Owner:        c.Owner,
-               Environment:  c.Environment,
-               MetadataType: c.MetadataType,
-               Tag:          c.Tag,
+               Organization:            c.Organization,
+               Name:                    c.Name,
+               Module:                  c.Module,
+               Group:                   c.Group,
+               Version:                 c.Version,
+               Owner:                   c.Owner,
+               Environment:             c.Environment,
+               MetadataType:            c.MetadataType,
+               Tag:                     c.Tag,
+               MetadataServicePort:     c.MetadataServicePort,
+               MetadataServiceProtocol: c.MetadataServiceProtocol,
        }
 }
 
diff --git a/config/application_config.go b/config/application_config.go
index 69a7636e2..c245c8a5e 100644
--- a/config/application_config.go
+++ b/config/application_config.go
@@ -17,6 +17,10 @@
 
 package config
 
+import (
+       "strconv"
+)
+
 import (
        "github.com/creasty/defaults"
 
@@ -37,9 +41,10 @@ type ApplicationConfig struct {
        Owner        string `default:"dubbo-go" yaml:"owner" 
json:"owner,omitempty" property:"owner"`
        Environment  string `yaml:"environment" json:"environment,omitempty" 
property:"environment"`
        // the metadata type. remote or local
-       MetadataType        string `default:"local" yaml:"metadata-type" 
json:"metadataType,omitempty" property:"metadataType"`
-       Tag                 string `yaml:"tag" json:"tag,omitempty" 
property:"tag"`
-       MetadataServicePort string `yaml:"metadata-service-port" 
json:"metadata-service-port,omitempty" property:"metadata-service-port"`
+       MetadataType            string `default:"local" yaml:"metadata-type" 
json:"metadataType,omitempty" property:"metadataType"`
+       Tag                     string `yaml:"tag" json:"tag,omitempty" 
property:"tag"`
+       MetadataServicePort     string `yaml:"metadata-service-port" 
json:"metadata-service-port,omitempty" property:"metadata-service-port"`
+       MetadataServiceProtocol string `yaml:"metadata-service-protocol" 
json:"metadata-service-protocol,omitempty" property:"metadata-service-protocol"`
 }
 
 // Prefix dubbo.application
@@ -111,6 +116,16 @@ func (acb *ApplicationConfigBuilder) 
SetMetadataType(metadataType string) *Appli
        return acb
 }
 
+func (acb *ApplicationConfigBuilder) SetMetadataServicePort(port int) 
*ApplicationConfigBuilder {
+       acb.application.MetadataServicePort = strconv.Itoa(port)
+       return acb
+}
+
+func (acb *ApplicationConfigBuilder) SetMetadataServiceProtocol(protocol 
string) *ApplicationConfigBuilder {
+       acb.application.MetadataServiceProtocol = protocol
+       return acb
+}
+
 func (acb *ApplicationConfigBuilder) Build() *ApplicationConfig {
        return acb.application
 }
diff --git a/config/root_config.go b/config/root_config.go
index 8239b1e10..12f835df0 100644
--- a/config/root_config.go
+++ b/config/root_config.go
@@ -38,6 +38,7 @@ import (
        "dubbo.apache.org/dubbo-go/v3/common/constant"
        "dubbo.apache.org/dubbo-go/v3/common/extension"
        "dubbo.apache.org/dubbo-go/v3/config_center"
+       "dubbo.apache.org/dubbo-go/v3/metadata/service"
        "dubbo.apache.org/dubbo-go/v3/metadata/service/exporter"
 )
 
@@ -347,9 +348,26 @@ func (rb *RootConfigBuilder) Build() *RootConfig {
 }
 
 func exportMetadataService() {
-       ms, err := extension.GetLocalMetadataService(constant.DefaultKey)
+       var (
+               err  error
+               ms   service.MetadataService
+               msV1 service.MetadataServiceV1
+               msV2 service.MetadataServiceV2
+       )
+
+       ms, err = extension.GetLocalMetadataService(constant.DefaultKey)
        if err != nil {
-               logger.Warnf("could not init metadata service", err)
+               logger.Warn("could not init metadata service", err)
+               return
+       }
+       msV1, err = 
extension.GetLocalMetadataServiceV1(constant.MetadataServiceV1)
+       if err != nil {
+               logger.Warn("could not init metadata service", err)
+               return
+       }
+       msV2, err = 
extension.GetLocalMetadataServiceV2(constant.MetadataServiceV2)
+       if err != nil {
+               logger.Warn("could not init metadata service", err)
                return
        }
 
@@ -364,23 +382,18 @@ func exportMetadataService() {
        // So using sync.Once will result in dead lock
        exporting.Store(true)
 
-       expt := extension.GetMetadataServiceExporter(constant.DefaultKey, ms)
+       expt := extension.GetMetadataServiceExporter(constant.DefaultKey, ms, 
msV1, msV2)
        if expt == nil {
                logger.Warnf("get metadata service exporter failed, pls check 
if you import _ 
\"dubbo.apache.org/dubbo-go/v3/metadata/service/exporter/configurable\"")
                return
        }
 
-       err = expt.Export(nil)
+       err = expt.Export()
        if err != nil {
                logger.Errorf("could not export the metadata service, err = 
%s", err.Error())
                return
        }
 
-       // report interface-app mapping
-       err = publishMapping(expt)
-       if err != nil {
-               logger.Errorf("Publish interface-application mapping failed, 
got error %#v", err)
-       }
 }
 
 // OnEvent only handle ServiceConfigExportedEvent
diff --git a/config/service_config.go b/config/service_config.go
index 0454b6aca..a60bd631c 100644
--- a/config/service_config.go
+++ b/config/service_config.go
@@ -32,7 +32,6 @@ import (
        "github.com/creasty/defaults"
 
        "github.com/dubbogo/gost/log/logger"
-       gxnet "github.com/dubbogo/gost/net"
 
        perrors "github.com/pkg/errors"
 
@@ -222,12 +221,7 @@ func getRandomPort(protocolConfigs []*ProtocolConfig) 
*list.List {
                        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])
+               ports.PushBack(common.GetRandomPort(proto.Ip))
        }
        return ports
 }
@@ -327,16 +321,6 @@ func (s *ServiceConfig) Export() error {
                                s.exporters = append(s.exporters, exporter)
                        }
                } else {
-                       if ivkURL.GetParam(constant.InterfaceKey, "") == 
constant.MetadataServiceName {
-                               ms, err := extension.GetLocalMetadataService("")
-                               if err != nil {
-                                       logger.Warnf("export 
org.apache.dubbo.metadata.MetadataService failed beacause of %s ! pls check if 
you import _ \"dubbo.apache.org/dubbo-go/v3/metadata/service/local\"", err)
-                                       return nil
-                               }
-                               if err := ms.SetMetadataServiceURL(ivkURL); err 
!= nil {
-                                       logger.Warnf("SetMetadataServiceURL 
error = %s", err)
-                               }
-                       }
                        invoker = s.generatorInvoker(ivkURL, info)
                        exporter := 
extension.GetProtocol(protocolwrapper.FILTER).Export(invoker)
                        if exporter == nil {
diff --git a/global/application_config.go b/global/application_config.go
index 0eab19d8e..e01c08261 100644
--- a/global/application_config.go
+++ b/global/application_config.go
@@ -27,8 +27,10 @@ type ApplicationConfig struct {
        Owner        string `default:"dubbo-go" yaml:"owner" 
json:"owner,omitempty" property:"owner"`
        Environment  string `yaml:"environment" json:"environment,omitempty" 
property:"environment"`
        // the metadata type. remote or local
-       MetadataType string `default:"local" yaml:"metadata-type" 
json:"metadataType,omitempty" property:"metadataType"`
-       Tag          string `yaml:"tag" json:"tag,omitempty" property:"tag"`
+       MetadataType            string `default:"local" yaml:"metadata-type" 
json:"metadataType,omitempty" property:"metadataType"`
+       Tag                     string `yaml:"tag" json:"tag,omitempty" 
property:"tag"`
+       MetadataServicePort     string `yaml:"metadata-service-port" 
json:"metadata-service-port,omitempty" property:"metadata-service-port"`
+       MetadataServiceProtocol string `yaml:"metadata-service-protocol" 
json:"metadata-service-protocol,omitempty" property:"metadata-service-protocol"`
 }
 
 func DefaultApplicationConfig() *ApplicationConfig {
@@ -43,14 +45,16 @@ func (c *ApplicationConfig) Clone() *ApplicationConfig {
        }
 
        return &ApplicationConfig{
-               Organization: c.Organization,
-               Name:         c.Name,
-               Module:       c.Module,
-               Group:        c.Group,
-               Version:      c.Version,
-               Owner:        c.Owner,
-               Environment:  c.Environment,
-               MetadataType: c.MetadataType,
-               Tag:          c.Tag,
+               Organization:            c.Organization,
+               Name:                    c.Name,
+               Module:                  c.Module,
+               Group:                   c.Group,
+               Version:                 c.Version,
+               Owner:                   c.Owner,
+               Environment:             c.Environment,
+               MetadataType:            c.MetadataType,
+               Tag:                     c.Tag,
+               MetadataServicePort:     c.MetadataServicePort,
+               MetadataServiceProtocol: c.MetadataServiceProtocol,
        }
 }
diff --git a/metadata/metadata.go b/metadata/metadata.go
index d4fa2c494..d5a76c7f0 100644
--- a/metadata/metadata.go
+++ b/metadata/metadata.go
@@ -21,15 +21,13 @@ package metadata
 import (
        "github.com/dubbogo/gost/log/logger"
 
-       perrors "github.com/pkg/errors"
-
        "go.uber.org/atomic"
 )
 
 import (
        "dubbo.apache.org/dubbo-go/v3/common/constant"
        "dubbo.apache.org/dubbo-go/v3/common/extension"
-       "dubbo.apache.org/dubbo-go/v3/metadata/service/exporter"
+       "dubbo.apache.org/dubbo-go/v3/metadata/service"
 )
 
 var (
@@ -37,9 +35,26 @@ var (
 )
 
 func ExportMetadataService() {
-       ms, err := extension.GetLocalMetadataService(constant.DefaultKey)
+       var (
+               err  error
+               ms   service.MetadataService
+               msV1 service.MetadataServiceV1
+               msV2 service.MetadataServiceV2
+       )
+
+       ms, err = extension.GetLocalMetadataService(constant.DefaultKey)
+       if err != nil {
+               logger.Warn("could not init metadata service", err)
+               return
+       }
+       msV1, err = 
extension.GetLocalMetadataServiceV1(constant.MetadataServiceV1)
+       if err != nil {
+               logger.Warn("could not init metadata service", err)
+               return
+       }
+       msV2, err = 
extension.GetLocalMetadataServiceV2(constant.MetadataServiceV2)
        if err != nil {
-               logger.Warnf("could not init metadata service", err)
+               logger.Warn("could not init metadata service", err)
                return
        }
 
@@ -54,34 +69,15 @@ func ExportMetadataService() {
        // So using sync.Once will result in dead lock
        exporting.Store(true)
 
-       expt := extension.GetMetadataServiceExporter(constant.DefaultKey, ms)
+       expt := extension.GetMetadataServiceExporter(constant.DefaultKey, ms, 
msV1, msV2)
        if expt == nil {
                logger.Warnf("get metadata service exporter failed, pls check 
if you import _ 
\"dubbo.apache.org/dubbo-go/v3/metadata/service/exporter/configurable\"")
                return
        }
 
-       err = expt.Export(nil)
+       err = expt.Export()
        if err != nil {
                logger.Errorf("could not export the metadata service, err = 
%s", err.Error())
                return
        }
-
-       // report interface-app mapping
-       err = publishMapping(expt)
-       if err != nil {
-               logger.Errorf("Publish interface-application mapping failed, 
got error %#v", err)
-       }
-}
-
-// OnEvent only handle ServiceConfigExportedEvent
-func publishMapping(sc exporter.MetadataServiceExporter) error {
-       urls := sc.GetExportedURLs()
-
-       for _, u := range urls {
-               err := extension.GetGlobalServiceNameMapping().Map(u)
-               if err != nil {
-                       return perrors.WithMessage(err, "could not map the 
service: "+u.String())
-               }
-       }
-       return nil
 }
diff --git a/metadata/service/exporter/configurable/exporter.go 
b/metadata/service/exporter/configurable/exporter.go
index 6fcdc444a..3cffeb9e1 100644
--- a/metadata/service/exporter/configurable/exporter.go
+++ b/metadata/service/exporter/configurable/exporter.go
@@ -18,6 +18,7 @@
 package configurable
 
 import (
+       "strings"
        "sync"
 )
 
@@ -34,14 +35,21 @@ import (
        "dubbo.apache.org/dubbo-go/v3/metadata/service"
        "dubbo.apache.org/dubbo-go/v3/metadata/service/exporter"
        _ "dubbo.apache.org/dubbo-go/v3/metadata/service/remote"
+       "dubbo.apache.org/dubbo-go/v3/protocol"
        _ "dubbo.apache.org/dubbo-go/v3/protocol/dubbo"
+       "dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper"
+       "dubbo.apache.org/dubbo-go/v3/server"
 )
 
 // MetadataServiceExporter is the ConfigurableMetadataServiceExporter which 
implement MetadataServiceExporter interface
 type MetadataServiceExporter struct {
-       ServiceConfig   *config.ServiceConfig
-       lock            sync.RWMutex
-       metadataService service.MetadataService
+       ServiceConfig     *config.ServiceConfig
+       v2Exporter        protocol.Exporter
+       Exporter          protocol.Exporter
+       lock              sync.RWMutex
+       metadataService   service.MetadataService
+       metadataServiceV1 service.MetadataServiceV1
+       metadataServiceV2 service.MetadataServiceV2
 }
 
 func init() {
@@ -49,24 +57,39 @@ func init() {
 }
 
 // NewMetadataServiceExporter will return a 
service_exporter.MetadataServiceExporter with the specified  metadata service
-func NewMetadataServiceExporter(metadataService service.MetadataService) 
exporter.MetadataServiceExporter {
+func NewMetadataServiceExporter(metadataService service.MetadataService, 
metadataServiceV1 service.MetadataServiceV1, metadataServiceV2 
service.MetadataServiceV2) exporter.MetadataServiceExporter {
        return &MetadataServiceExporter{
-               metadataService: metadataService,
+               metadataService:   metadataService,
+               metadataServiceV1: metadataServiceV1,
+               metadataServiceV2: metadataServiceV2,
        }
 }
 
 // Export will export the metadataService
-func (exporter *MetadataServiceExporter) Export(url *common.URL) error {
+func (exporter *MetadataServiceExporter) Export() error {
        if !exporter.IsExported() {
-               version, _ := exporter.metadataService.Version()
                exporter.lock.Lock()
                defer exporter.lock.Unlock()
+               var err error
+               pro, port := getMetadataProtocolAndPort()
+               err = exporter.exportV1(pro, port)
+               if err != nil {
+                       return err
+               }
+               err = exporter.exportV2(pro, port)
+               return err
+       }
+       logger.Warnf("[Metadata Service] The MetadataService has been exported 
: %v ", exporter.ServiceConfig.GetExportedUrls())
+       return nil
+}
+
+func (exporter *MetadataServiceExporter) exportV1(pro, port string) error {
+       version, _ := exporter.metadataService.Version()
+       if pro == constant.DefaultProtocol {
                exporter.ServiceConfig = config.NewServiceConfigBuilder().
                        SetServiceID(constant.SimpleMetadataServiceName).
-                       SetProtocolIDs(constant.DefaultProtocol).
-                       AddRCProtocol(constant.DefaultProtocol, 
config.NewProtocolConfigBuilder().
-                               
SetName(constant.DefaultProtocol).SetPort(getMetadataPort()).
-                               Build()).
+                       SetProtocolIDs(pro).
+                       AddRCProtocol(pro, 
config.NewProtocolConfigBuilder().SetName(pro).SetPort(port).Build()).
                        SetRegistryIDs("N/A").
                        SetInterface(constant.MetadataServiceName).
                        SetGroup(config.GetApplicationConfig().Name).
@@ -76,46 +99,133 @@ func (exporter *MetadataServiceExporter) Export(url 
*common.URL) error {
                        Build()
                exporter.ServiceConfig.Implement(exporter.metadataService)
                err := exporter.ServiceConfig.Export()
-
-               logger.Infof("[Metadata Service] The MetadataService exports 
urls : %v ", exporter.ServiceConfig.GetExportedUrls())
+               logger.Infof("[Metadata Service] MetadataService has been 
exported at url : %v ", exporter.ServiceConfig.GetExportedUrls())
+               
exporter.metadataService.SetMetadataServiceURL(exporter.ServiceConfig.GetExportedUrls()[0])
                return err
+       } else {
+               info := server.MetadataService_ServiceInfo
+
+               ivkURL := common.NewURLWithOptions(
+                       common.WithPath(constant.MetadataServiceName),
+                       common.WithProtocol(constant.TriProtocol),
+                       common.WithPort(port),
+                       common.WithParamsValue(constant.GroupKey, 
config.GetApplicationConfig().Name),
+                       common.WithParamsValue(constant.VersionKey, version),
+                       common.WithInterface(constant.MetadataServiceName),
+                       
common.WithMethods(strings.Split("getMetadataInfo,GetMetadataInfo", ",")),
+                       common.WithAttribute(constant.ServiceInfoKey, &info),
+                       common.WithParamsValue(constant.SerializationKey, 
constant.Hessian2Serialization),
+               )
+
+               invoker := server.NewInternalInvoker(ivkURL, &info, 
exporter.metadataServiceV1)
+               exporter.Exporter = 
extension.GetProtocol(protocolwrapper.FILTER).Export(invoker)
+               logger.Infof("[Metadata Service] MetadataService has been 
exported at url : %v ", invoker.GetURL())
+               exporter.metadataService.SetMetadataServiceURL(invoker.GetURL())
+               return nil
        }
-       logger.Warnf("[Metadata Service] The MetadataService has been exported 
: %v ", exporter.ServiceConfig.GetExportedUrls())
+}
+
+func (exporter *MetadataServiceExporter) exportV2(pro, port string) error {
+       info := server.MetadataServiceV2_ServiceInfo
+       // v2 only supports triple protocol
+       if pro == constant.DefaultProtocol {
+               return nil
+       }
+       ivkURL := common.NewURLWithOptions(
+               common.WithPath(constant.MetadataServiceV2Name),
+               common.WithProtocol(constant.TriProtocol),
+               common.WithPort(port),
+               common.WithParamsValue(constant.GroupKey, 
config.GetApplicationConfig().Name),
+               common.WithParamsValue(constant.VersionKey, "2.0.0"),
+               common.WithInterface(constant.MetadataServiceV2Name),
+               
common.WithMethods(strings.Split("getMetadataInfo,GetMetadataInfo", ",")),
+               common.WithAttribute(constant.ServiceInfoKey, &info),
+       )
+
+       invoker := server.NewInternalInvoker(ivkURL, &info, 
exporter.metadataServiceV2)
+       exporter.v2Exporter = 
extension.GetProtocol(protocolwrapper.FILTER).Export(invoker)
+       logger.Infof("[Metadata Service] MetadataServiceV2 has been exported at 
url : %v ", invoker.GetURL())
+       // do not set, because it will override MetadataService
+       //exporter.metadataService.SetMetadataServiceURL(ivkURL)
        return nil
 }
 
-func getMetadataPort() string {
+func getMetadataProtocolAndPort() (string, string) {
        rootConfig := config.GetRootConfig()
        port := rootConfig.Application.MetadataServicePort
-       if port == "" {
-               protocolConfig, ok := 
rootConfig.Protocols[constant.DefaultProtocol]
-               if ok {
-                       port = protocolConfig.Port
+       protocol := rootConfig.Application.MetadataServiceProtocol
+       if protocol != "" && port != "" {
+               return protocol, port
+       }
+
+       var protocolConfig *config.ProtocolConfig
+       for _, pc := range rootConfig.Protocols {
+               if pc.Name != constant.DefaultProtocol && pc.Name != 
constant.TriProtocol {
+                       continue
+               }
+               if pc.Name == protocol {
+                       protocolConfig = pc
+                       break
+               }
+       }
+
+       if protocol == "" {
+               for _, pc := range rootConfig.Protocols {
+                       if pc.Name == constant.TriProtocol {
+                               protocolConfig = pc
+                               break
+                       }
+               }
+       }
+
+       if protocolConfig == nil {
+               port = common.GetRandomPort("0")
+               if protocol == "" || protocol == constant.TriProtocol {
+                       protocolConfig = &config.ProtocolConfig{
+                               Name: constant.TriProtocol,
+                               Port: port, // use a random port
+                       }
                } else {
-                       logger.Warnf("[Metadata Service] Dubbo-go %s version's 
MetadataService only support dubbo protocol,"+
-                               "MetadataService will use random port",
-                               constant.Version)
+                       protocolConfig = &config.ProtocolConfig{
+                               Name: constant.DefaultProtocol,
+                               Port: port, // use a random port
+                       }
                }
        }
-       return port
+
+       if port == "" {
+               return protocolConfig.Name, protocolConfig.Port
+       } else {
+               return protocolConfig.Name, port
+       }
 }
 
 // Unexport will unexport the metadataService
 func (exporter *MetadataServiceExporter) Unexport() {
-       if exporter.IsExported() {
+       if exporter.IsExported() && exporter.ServiceConfig != nil {
                exporter.ServiceConfig.Unexport()
+               exporter.ServiceConfig = nil
+       }
+       if exporter.v2Exporter != nil {
+               exporter.v2Exporter.UnExport()
+               exporter.v2Exporter = nil
+       }
+       if exporter.Exporter != nil {
+               exporter.Exporter.UnExport()
+               exporter.Exporter = nil
        }
 }
 
 // GetExportedURLs will return the urls that export use.
 // Notice!The exported url is not same as url in registry , for example it 
lack the ip.
 func (exporter *MetadataServiceExporter) GetExportedURLs() []*common.URL {
-       return exporter.ServiceConfig.GetExportedUrls()
+       url, _ := exporter.metadataService.GetMetadataServiceURL()
+       return []*common.URL{url}
 }
 
 // IsExported will return is metadataServiceExporter exported or not
 func (exporter *MetadataServiceExporter) IsExported() bool {
        exporter.lock.RLock()
        defer exporter.lock.RUnlock()
-       return exporter.ServiceConfig != nil && 
exporter.ServiceConfig.IsExport()
+       return exporter.ServiceConfig != nil && 
exporter.ServiceConfig.IsExport() || exporter.Exporter != nil
 }
diff --git a/metadata/service/exporter/configurable/exporter_test.go 
b/metadata/service/exporter/configurable/exporter_test.go
index aeb260cfd..dc7ed3709 100644
--- a/metadata/service/exporter/configurable/exporter_test.go
+++ b/metadata/service/exporter/configurable/exporter_test.go
@@ -26,12 +26,12 @@ import (
 )
 
 import (
-       "dubbo.apache.org/dubbo-go/v3/common"
        "dubbo.apache.org/dubbo-go/v3/config"
        _ "dubbo.apache.org/dubbo-go/v3/filter/filter_impl"
        "dubbo.apache.org/dubbo-go/v3/metadata/service/local"
        _ "dubbo.apache.org/dubbo-go/v3/metrics/prometheus"
        _ "dubbo.apache.org/dubbo-go/v3/protocol/dubbo"
+       _ "dubbo.apache.org/dubbo-go/v3/protocol/triple"
        _ "dubbo.apache.org/dubbo-go/v3/proxy/proxy_factory"
        "dubbo.apache.org/dubbo-go/v3/remoting/getty"
 )
@@ -56,16 +56,15 @@ func TestConfigurableExporter(t *testing.T) {
        })
        mockInitProviderWithSingleRegistry()
        metadataService, _ := local.GetLocalMetadataService()
-       exported := NewMetadataServiceExporter(metadataService)
+       metadataServiceV1, _ := local.GetLocalMetadataServiceV1()
+       metadataServiceV2, _ := local.GetLocalMetadataServiceV2()
+       exported := NewMetadataServiceExporter(metadataService, 
metadataServiceV1, metadataServiceV2)
 
        t.Run("configurableExporter", func(t *testing.T) {
-               registryURL, _ := 
common.NewURL("service-discovery://localhost:12345")
-               subURL, _ := common.NewURL("dubbo://localhost:20003")
-               registryURL.SubURL = subURL
                assert.Equal(t, false, exported.IsExported())
-               assert.NoError(t, exported.Export(registryURL))
+               assert.NoError(t, exported.Export())
                assert.Equal(t, true, exported.IsExported())
-               assert.Regexp(t, 
"dubbo://:[0-9]{1,}/org.apache.dubbo.metadata.MetadataService*", 
exported.GetExportedURLs()[0].String())
+               assert.Regexp(t, 
"tri://:[0-9]{1,}/org.apache.dubbo.metadata.MetadataService*", 
exported.GetExportedURLs()[0].String())
                exported.Unexport()
                assert.Equal(t, false, exported.IsExported())
        })
diff --git a/metadata/service/exporter/exporter.go 
b/metadata/service/exporter/exporter.go
index ab4e2fedd..1dc3c9454 100644
--- a/metadata/service/exporter/exporter.go
+++ b/metadata/service/exporter/exporter.go
@@ -23,7 +23,7 @@ import (
 
 // MetadataServiceExporter will export & unexport the metadata service,  get 
exported url, and return is exported or not
 type MetadataServiceExporter interface {
-       Export(url *common.URL) error
+       Export() error
        Unexport()
        GetExportedURLs() []*common.URL
        IsExported() bool
diff --git a/metadata/service/local/metadata_service_proxy_factory.go 
b/metadata/service/local/metadata_service_proxy_factory.go
index 9645374b3..61d4f6a85 100644
--- a/metadata/service/local/metadata_service_proxy_factory.go
+++ b/metadata/service/local/metadata_service_proxy_factory.go
@@ -36,9 +36,13 @@ import (
 
 func init() {
        factory := service.NewBaseMetadataServiceProxyFactory(createProxy)
+       factoryV2 := service.NewBaseMetadataServiceProxyFactoryV2(createProxyV2)
        extension.SetMetadataServiceProxyFactory(constant.DefaultKey, func() 
service.MetadataServiceProxyFactory {
                return factory
        })
+       extension.SetMetadataServiceProxyFactoryV2(constant.MetadataServiceV2, 
func() service.MetadataServiceProxyFactoryV2 {
+               return factoryV2
+       })
 }
 
 var (
@@ -75,43 +79,83 @@ func createProxy(ins registry.ServiceInstance) 
service.MetadataService {
        }
 }
 
+func createProxyV2(ins registry.ServiceInstance) service.MetadataServiceV2 {
+       urls := buildStandardMetadataServiceURL(ins)
+       if len(urls) == 0 {
+               logger.Errorf("metadata service urls not found, %v", ins)
+               return nil
+       }
+
+       u := urls[0]
+       p := extension.GetProtocol(u.Protocol)
+       invoker := p.Refer(u)
+       if invoker == nil { // can't connect instance
+               return nil
+       }
+       return &MetadataServiceProxyV2{
+               Invoker: invoker,
+       }
+}
+
 // buildStandardMetadataServiceURL will use standard format to build the 
metadata service url.
 func buildStandardMetadataServiceURL(ins registry.ServiceInstance) 
[]*common.URL {
        ps := getMetadataServiceUrlParams(ins)
        if ps[constant.ProtocolKey] == "" {
                return nil
        }
+
        res := make([]*common.URL, 0, len(ps))
        sn := ins.GetServiceName()
        host := ins.GetHost()
+
+       metaV := ins.GetMetadata()[constant.MetadataVersion]
+       protocol := ps[constant.ProtocolKey]
+       if metaV == constant.MetadataServiceV2Version {
+               protocol = constant.TriProtocol
+       }
+
        convertedParams := make(map[string][]string, len(ps))
        for k, v := range ps {
                convertedParams[k] = []string{v}
        }
        u := common.NewURLWithOptions(common.WithIp(host),
                common.WithPath(constant.MetadataServiceName),
-               common.WithProtocol(ps[constant.ProtocolKey]),
+               common.WithProtocol(protocol),
                common.WithPort(ps[constant.PortKey]),
                common.WithParams(convertedParams),
                common.WithParamsValue(constant.GroupKey, sn),
                common.WithParamsValue(constant.InterfaceKey, 
constant.MetadataServiceName))
+
+       if protocol == constant.TriProtocol {
+               u.SetAttribute(constant.ClientInfoKey, "info")
+               u.Methods = []string{"GetMetadataInfo", "getMetadataInfo"}
+               if metaV == constant.MetadataServiceV2Version {
+                       u.Path = constant.MetadataServiceV2Name
+                       u.SetParam(constant.VersionKey, metaV)
+                       u.SetParam(constant.InterfaceKey, 
constant.MetadataServiceV2Name)
+                       u.DelParam(constant.SerializationKey)
+               } else {
+                       u.SetParam(constant.SerializationKey, 
constant.Hessian2Serialization)
+               }
+       }
+
        res = append(res, u)
 
        return res
 }
 
-// getMetadataServiceUrlParams this will convert the metadata service url 
parameters to map structure
+// getMetadataServiceUrlParams this will convertV2 the metadata service url 
parameters to map structure
 // it looks like:
 // 
{"dubbo":{"timeout":"10000","version":"1.0.0","dubbo":"2.0.2","release":"2.7.6","port":"20880"}}
 func getMetadataServiceUrlParams(ins registry.ServiceInstance) 
map[string]string {
        ps := ins.GetMetadata()
        res := make(map[string]string, 2)
        if str, ok := ps[constant.MetadataServiceURLParamsPropertyName]; ok && 
len(str) > 0 {
-
                err := json.Unmarshal([]byte(str), &res)
                if err != nil {
                        logger.Errorf("could not parse the metadata service url 
parameters to map", err)
                }
        }
+
        return res
 }
diff --git a/metadata/service/local/service.go 
b/metadata/service/local/service.go
index 440953e07..3b72af3d7 100644
--- a/metadata/service/local/service.go
+++ b/metadata/service/local/service.go
@@ -18,6 +18,7 @@
 package local
 
 import (
+       "context"
        "sort"
        "sync"
 )
@@ -35,10 +36,13 @@ import (
        "dubbo.apache.org/dubbo-go/v3/config"
        "dubbo.apache.org/dubbo-go/v3/metadata/definition"
        "dubbo.apache.org/dubbo-go/v3/metadata/service"
+       triple_api "dubbo.apache.org/dubbo-go/v3/metadata/triple_api/proto"
 )
 
 func init() {
        extension.SetLocalMetadataService(constant.DefaultKey, 
GetLocalMetadataService)
+       extension.SetLocalMetadataServiceV1(constant.MetadataServiceV1, 
GetLocalMetadataServiceV1)
+       extension.SetLocalMetadataServiceV2(constant.MetadataServiceV2, 
GetLocalMetadataServiceV2)
 }
 
 // version will be used by Version func
@@ -61,6 +65,12 @@ type MetadataService struct {
 var (
        metadataServiceInstance *MetadataService
        metadataServiceInitOnce sync.Once
+
+       metadataServiceV2Instance *MetadataServiceV2
+       metadataServiceV2InitOnce sync.Once
+
+       metadataServiceV1Instance *MetadataServiceV1
+       metadataServiceV1InitOnce sync.Once
 )
 
 // GetLocalMetadataService which should be singleton initiates a metadata 
service
@@ -280,3 +290,85 @@ func (mts *MetadataService) SetMetadataServiceURL(url 
*common.URL) error {
        mts.metadataServiceURL = url
        return nil
 }
+
+func GetLocalMetadataServiceV1() (service.MetadataServiceV1, error) {
+       metadataServiceV1InitOnce.Do(func() {
+               delegate, _ := GetLocalMetadataService()
+               metadataServiceV1Instance = &MetadataServiceV1{
+                       delegate: delegate,
+               }
+       })
+       return metadataServiceV1Instance, nil
+}
+
+type MetadataServiceV1 struct {
+       service.BaseMetadataService
+       delegate service.MetadataService
+}
+
+func (mtsV1 *MetadataServiceV1) GetMetadataInfo(ctx context.Context, revision 
string) (*triple_api.MetadataInfo, error) {
+       metadataInfo, err := mtsV1.delegate.GetMetadataInfo(revision)
+       return &triple_api.MetadataInfo{
+               App:      metadataInfo.App,
+               Version:  metadataInfo.Revision,
+               Services: convertV1(metadataInfo.Services),
+       }, err
+}
+
+func convertV1(serviceInfos map[string]*common.ServiceInfo) 
map[string]*triple_api.ServiceInfo {
+       serviceInfoV1s := make(map[string]*triple_api.ServiceInfo, 
len(serviceInfos))
+       for k, info := range serviceInfos {
+               serviceInfo := &triple_api.ServiceInfo{
+                       Name:     info.Name,
+                       Group:    info.Group,
+                       Version:  info.Version,
+                       Protocol: info.Protocol,
+                       Port:     0,
+                       Path:     info.Path,
+                       Params:   info.Params,
+               }
+               serviceInfoV1s[k] = serviceInfo
+       }
+       return serviceInfoV1s
+}
+
+func GetLocalMetadataServiceV2() (service.MetadataServiceV2, error) {
+       metadataServiceV2InitOnce.Do(func() {
+               delegate, _ := GetLocalMetadataService()
+               metadataServiceV2Instance = &MetadataServiceV2{
+                       delegate: delegate,
+               }
+       })
+       return metadataServiceV2Instance, nil
+}
+
+type MetadataServiceV2 struct {
+       service.BaseMetadataService
+       delegate service.MetadataService
+}
+
+func (mtsV2 *MetadataServiceV2) GetMetadataInfo(ctx context.Context, req 
*triple_api.MetadataRequest) (*triple_api.MetadataInfoV2, error) {
+       metadataInfo, err := mtsV2.delegate.GetMetadataInfo(req.GetRevision())
+       return &triple_api.MetadataInfoV2{
+               App:      metadataInfo.App,
+               Version:  metadataInfo.Revision,
+               Services: convertV2(metadataInfo.Services),
+       }, err
+}
+
+func convertV2(serviceInfos map[string]*common.ServiceInfo) 
map[string]*triple_api.ServiceInfoV2 {
+       serviceInfoV2s := make(map[string]*triple_api.ServiceInfoV2, 
len(serviceInfos))
+       for k, info := range serviceInfos {
+               serviceInfoV2 := &triple_api.ServiceInfoV2{
+                       Name:     info.Name,
+                       Group:    info.Group,
+                       Version:  info.Version,
+                       Protocol: info.Protocol,
+                       Port:     0,
+                       Path:     info.Path,
+                       Params:   info.Params,
+               }
+               serviceInfoV2s[k] = serviceInfoV2
+       }
+       return serviceInfoV2s
+}
diff --git a/metadata/service/local/service_proxy.go 
b/metadata/service/local/service_proxy.go
index 47421b110..cc4abaed8 100644
--- a/metadata/service/local/service_proxy.go
+++ b/metadata/service/local/service_proxy.go
@@ -29,6 +29,7 @@ import (
 import (
        "dubbo.apache.org/dubbo-go/v3/common"
        "dubbo.apache.org/dubbo-go/v3/common/constant"
+       triple_api "dubbo.apache.org/dubbo-go/v3/metadata/triple_api/proto"
        "dubbo.apache.org/dubbo-go/v3/protocol"
        "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
 )
@@ -173,18 +174,90 @@ func (m *MetadataServiceProxy) Version() (string, error) {
 
 // nolint
 func (m *MetadataServiceProxy) GetMetadataInfo(revision string) 
(*common.MetadataInfo, error) {
-       rV := reflect.ValueOf(revision)
        const methodName = "getMetadataInfo"
-       inv := 
invocation.NewRPCInvocationWithOptions(invocation.WithMethodName(methodName),
-               invocation.WithArguments([]interface{}{rV.Interface()}),
-               
invocation.WithReply(reflect.ValueOf(&common.MetadataInfo{}).Interface()),
-               
invocation.WithAttachments(map[string]interface{}{constant.AsyncKey: "false"}),
-               invocation.WithParameterValues([]reflect.Value{rV}))
+
+       metadataInfo := &triple_api.MetadataInfo{}
+
+       inv, _ := generateInvocation(m.Invoker.GetURL(), methodName, revision, 
metadataInfo, constant.CallUnary)
+       res := m.Invoker.Invoke(context.Background(), inv)
+       if res.Error() != nil {
+               logger.Errorf("could not get the metadata info from remote 
provider: %v", res.Error())
+               return nil, res.Error()
+       }
+
+       if metadataInfo.Services == nil {
+               metadataInfo = res.Result().(*triple_api.MetadataInfo)
+       }
+
+       return convertMetadataInfo(metadataInfo), nil
+}
+
+func convertMetadataInfo(v1 *triple_api.MetadataInfo) *common.MetadataInfo {
+       infos := make(map[string]*common.ServiceInfo, 0)
+       for k, v := range v1.Services {
+               info := &common.ServiceInfo{
+                       Name:     v.Name,
+                       Group:    v.Group,
+                       Version:  v.Version,
+                       Protocol: v.Protocol,
+                       Path:     v.Path,
+                       Params:   v.Params,
+               }
+               infos[k] = info
+       }
+
+       metadataInfo := &common.MetadataInfo{
+               Reported: false,
+               App:      v1.App,
+               Revision: v1.Version,
+               Services: infos,
+       }
+       return metadataInfo
+}
+
+type MetadataServiceProxyV2 struct {
+       Invoker protocol.Invoker
+}
+
+func (m *MetadataServiceProxyV2) GetMetadataInfo(ctx context.Context, req 
*triple_api.MetadataRequest) (*triple_api.MetadataInfoV2, error) {
+       const methodName = "GetMetadataInfo"
+
+       metadataInfo := &triple_api.MetadataInfoV2{}
+       inv, _ := generateInvocation(m.Invoker.GetURL(), methodName, req, 
metadataInfo, constant.CallUnary)
        res := m.Invoker.Invoke(context.Background(), inv)
        if res.Error() != nil {
                logger.Errorf("could not get the metadata info from remote 
provider: %v", res.Error())
                return nil, res.Error()
        }
-       metaDataInfo := res.Result().(*common.MetadataInfo)
-       return metaDataInfo, nil
+
+       return metadataInfo, nil
+}
+
+func generateInvocation(u *common.URL, methodName string, req interface{}, 
resp interface{}, callType string) (protocol.Invocation, error) {
+       var inv *invocation.RPCInvocation
+       if u.Protocol == constant.TriProtocol {
+               var paramsRawVals []interface{}
+               paramsRawVals = append(paramsRawVals, req)
+               if resp != nil {
+                       paramsRawVals = append(paramsRawVals, resp)
+               }
+               inv = invocation.NewRPCInvocationWithOptions(
+                       invocation.WithMethodName(methodName),
+                       invocation.WithAttachment(constant.TimeoutKey, "5000"),
+                       invocation.WithAttachment(constant.RetriesKey, "2"),
+                       invocation.WithArguments([]interface{}{req}),
+                       invocation.WithReply(resp),
+                       invocation.WithParameterRawValues(paramsRawVals),
+               )
+               inv.SetAttribute(constant.CallTypeKey, callType)
+       } else {
+               rV := reflect.ValueOf(req)
+               inv = 
invocation.NewRPCInvocationWithOptions(invocation.WithMethodName(methodName),
+                       invocation.WithArguments([]interface{}{rV.Interface()}),
+                       invocation.WithReply(resp),
+                       
invocation.WithAttachments(map[string]interface{}{constant.AsyncKey: "false"}),
+                       invocation.WithParameterValues([]reflect.Value{rV}))
+       }
+
+       return inv, nil
 }
diff --git a/metadata/service/local_service.go 
b/metadata/service/local_service.go
index 1251a9d4f..eb88998a8 100644
--- a/metadata/service/local_service.go
+++ b/metadata/service/local_service.go
@@ -18,12 +18,14 @@
 package service
 
 import (
+       "context"
        "sync"
 )
 
 import (
        "dubbo.apache.org/dubbo-go/v3/common"
        "dubbo.apache.org/dubbo-go/v3/common/constant"
+       triple_api "dubbo.apache.org/dubbo-go/v3/metadata/triple_api/proto"
        "dubbo.apache.org/dubbo-go/v3/registry"
 )
 
@@ -135,3 +137,33 @@ func ConvertURLArrToIntfArr(urls []*common.URL) 
[]interface{} {
        }
        return res
 }
+
+// MetadataServiceV2 is a client for the 
org.apache.dubbo.metadata.MetadataServiceV2 service.
+type MetadataServiceV2 interface {
+       GetMetadataInfo(ctx context.Context, req *triple_api.MetadataRequest) 
(*triple_api.MetadataInfoV2, error)
+}
+
+type MetadataServiceProxyFactoryV2 interface {
+       GetProxy(ins registry.ServiceInstance) MetadataServiceV2
+}
+
+type MetadataServiceProxyCreatorV2 func(ins registry.ServiceInstance) 
MetadataServiceV2
+
+type BaseMetadataServiceProxyFactoryV2 struct {
+       proxies sync.Map
+       creator MetadataServiceProxyCreatorV2
+}
+
+func (b *BaseMetadataServiceProxyFactoryV2) GetProxy(ins 
registry.ServiceInstance) MetadataServiceV2 {
+       return b.creator(ins)
+}
+
+func NewBaseMetadataServiceProxyFactoryV2(creator 
MetadataServiceProxyCreatorV2) *BaseMetadataServiceProxyFactoryV2 {
+       return &BaseMetadataServiceProxyFactoryV2{
+               creator: creator,
+       }
+}
+
+type MetadataServiceV1 interface {
+       GetMetadataInfo(ctx context.Context, req string) 
(*triple_api.MetadataInfo, error)
+}
diff --git a/metadata/triple_api/proto/hessian2_extend/hessian2_extend.proto 
b/metadata/triple_api/proto/hessian2_extend/hessian2_extend.proto
new file mode 100644
index 000000000..618ea19d9
--- /dev/null
+++ b/metadata/triple_api/proto/hessian2_extend/hessian2_extend.proto
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package hessian2_extend;
+
+option go_package = 
"dubbo.apache.org/dubbo-go/v3/proto/hessian2_extend;hessian2_extend";
+
+import "google/protobuf/descriptor.proto";
+
+message Hessian2MessageOptions {
+  string java_class_name = 1;
+  string reference_path = 2;
+  bool is_inheritance = 3;
+  bool extend_args = 4;
+}
+
+extend google.protobuf.MessageOptions {
+  optional Hessian2MessageOptions message_extend = 12345;
+}
+
+message Hessian2MethodOptions {
+  string method_name = 1;
+}
+
+extend google.protobuf.MethodOptions {
+  optional Hessian2MethodOptions method_extend = 12345;
+}
+
+message Hessian2ServiceOptions {
+  string interface_name = 1;
+}
+
+extend google.protobuf.ServiceOptions {
+  optional Hessian2ServiceOptions service_extend = 12345;
+}
+
+message Hessian2EnumOptions {
+  string java_class_name = 1;
+}
+
+extend google.protobuf.EnumOptions {
+  optional Hessian2EnumOptions enum_extend = 12345;
+}
\ No newline at end of file
diff --git a/metadata/service/exporter/exporter.go 
b/metadata/triple_api/proto/java8_time/java8_time.proto
similarity index 67%
copy from metadata/service/exporter/exporter.go
copy to metadata/triple_api/proto/java8_time/java8_time.proto
index ab4e2fedd..8f3cc58f6 100644
--- a/metadata/service/exporter/exporter.go
+++ b/metadata/triple_api/proto/java8_time/java8_time.proto
@@ -15,16 +15,34 @@
  * limitations under the License.
  */
 
-package exporter
-
-import (
-       "dubbo.apache.org/dubbo-go/v3/common"
-)
-
-// MetadataServiceExporter will export & unexport the metadata service,  get 
exported url, and return is exported or not
-type MetadataServiceExporter interface {
-       Export(url *common.URL) error
-       Unexport()
-       GetExportedURLs() []*common.URL
-       IsExported() bool
-}
+syntax = "proto3";
+
+package java8_time;
+
+option go_package = "dubbo.apache.org/dubbo-go/v3/proto/java8_time;java8_time";
+
+message Duration{}
+
+message Instant {}
+
+message LocalDate{}
+
+message LocalDateTime{}
+
+message LocalTime{}
+
+message MonthDay{}
+
+message OffsetDateTime{}
+
+message OffsetTime{}
+
+message Period{}
+
+message Year{}
+
+message YearMonth{}
+
+message ZoneOffSet{}
+
+message ZonedDateTime{}
\ No newline at end of file
diff --git a/metadata/triple_api/proto/java_exception/java_exception.proto 
b/metadata/triple_api/proto/java_exception/java_exception.proto
new file mode 100644
index 000000000..74454bac5
--- /dev/null
+++ b/metadata/triple_api/proto/java_exception/java_exception.proto
@@ -0,0 +1,196 @@
+/*
+ * 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.
+*/
+
+syntax = "proto3";
+
+package java_exception;
+
+option go_package = 
"dubbo.apache.org/dubbo-go/v3/proto/java_exception;java_exception";
+
+message Exception {}
+
+message AnnotationTypeMismatchException {}
+
+message ArithmeticException {}
+
+message ArrayIndexOutOfBoundsException {}
+
+message ArrayStoreException {}
+
+message BackingStoreException {}
+
+message BrokenBarrierException {}
+
+message CancellationException {}
+
+message ClassNotFoundException {}
+
+message ClassCastException {}
+
+message CloneNotSupportedException {}
+
+message CompletionException {}
+
+message ConcurrentModificationException {}
+
+message DataFormatException {}
+
+message DateTimeException {}
+
+message DateTimeParseException {}
+
+message DubboGenericException {}
+
+message DuplicateFormatFlagsException {}
+
+message EmptyStackException {}
+
+message EnumConstantNotPresentException {}
+
+message EOFException {}
+
+message ExecutionException {}
+
+message FileNotFoundException {}
+
+message FormatterClosedException {}
+
+message IllegalAccessException {}
+
+message IllegalArgumentException {}
+
+message IllegalClassFormatException {}
+
+message IllegalFormatCodePointException {}
+
+message IllegalFormatConversionException {}
+
+message IllegalFormatFlagsException {}
+
+message IllegalFormatPrecisionException {}
+
+message IllegalFormatWidthException {}
+
+message IllegalMonitorStateException {}
+
+message IllegalStateException {}
+
+message IllegalThreadStateException {}
+
+message IllformedLocaleException {}
+
+message IncompleteAnnotationException {}
+
+message IndexOutOfBoundsException {}
+
+message InputMismatchException {}
+
+message InstantiationException {}
+
+message InterruptedException {}
+
+message InterruptedIOException {}
+
+message InvalidClassException {}
+
+message InvalidObjectException {}
+
+message InvalidPreferencesFormatException {}
+
+message InvalidPropertiesFormatException {}
+
+message InvocationTargetException {}
+
+message IOException {}
+
+message JarException {}
+
+message LambdaConversionException {}
+
+message MalformedParameterizedTypeException {}
+
+message MalformedParametersException {}
+
+message MissingFormatArgumentException {}
+
+message MissingFormatWidthException {}
+
+message MissingResourceException {}
+
+message NegativeArraySizeException {}
+
+message NoSuchElementException {}
+
+message NoSuchFieldException {}
+
+message NoSuchMethodException {}
+
+message NotActiveException {}
+
+message NotSerializableException {}
+
+message NullPointerException {}
+
+message NumberFormatException {}
+
+message ObjectStreamException {}
+
+message OptionalDataException {}
+
+message ReflectiveOperationException {}
+
+message RejectedExecutionException {}
+
+message RuntimeException {}
+
+message SecurityException {}
+
+message StreamCorruptedException {}
+
+message StringIndexOutOfBoundsException {}
+
+message SyncFailedException {}
+
+message TimeoutException {}
+
+message TooManyListenersException {}
+
+message TypeNotPresentException {}
+
+message UncheckedIOException {}
+
+message UndeclaredThrowableException {}
+
+message UnknownFormatConversionException {}
+
+message UnknownFormatFlagsException {}
+
+message UnmodifiableClassException {}
+
+message UnsupportedOperationException {}
+
+message UnsupportedTemporalTypeException {}
+
+message UTFDataFormatException {}
+
+message WriteAbortedException {}
+
+message WrongMethodTypeException {}
+
+message ZipException {}
+
+message ZoneRulesException{}
diff --git a/metadata/service/exporter/exporter.go 
b/metadata/triple_api/proto/java_math/java_math.proto
similarity index 71%
copy from metadata/service/exporter/exporter.go
copy to metadata/triple_api/proto/java_math/java_math.proto
index ab4e2fedd..342e82024 100644
--- a/metadata/service/exporter/exporter.go
+++ b/metadata/triple_api/proto/java_math/java_math.proto
@@ -15,16 +15,12 @@
  * limitations under the License.
  */
 
-package exporter
+syntax = "proto3";
 
-import (
-       "dubbo.apache.org/dubbo-go/v3/common"
-)
+package java_math;
 
-// MetadataServiceExporter will export & unexport the metadata service,  get 
exported url, and return is exported or not
-type MetadataServiceExporter interface {
-       Export(url *common.URL) error
-       Unexport()
-       GetExportedURLs() []*common.URL
-       IsExported() bool
-}
+option go_package = "dubbo.apache.org/dubbo-go/v3/proto/java_math;java_math";
+
+message Decimal {}
+
+message Integer {}
diff --git a/metadata/service/exporter/exporter.go 
b/metadata/triple_api/proto/java_sql_time/java_sql_time.proto
similarity index 71%
copy from metadata/service/exporter/exporter.go
copy to metadata/triple_api/proto/java_sql_time/java_sql_time.proto
index ab4e2fedd..7e4f5114a 100644
--- a/metadata/service/exporter/exporter.go
+++ b/metadata/triple_api/proto/java_sql_time/java_sql_time.proto
@@ -15,16 +15,12 @@
  * limitations under the License.
  */
 
-package exporter
+syntax = "proto3";
 
-import (
-       "dubbo.apache.org/dubbo-go/v3/common"
-)
+package java_sql_time;
 
-// MetadataServiceExporter will export & unexport the metadata service,  get 
exported url, and return is exported or not
-type MetadataServiceExporter interface {
-       Export(url *common.URL) error
-       Unexport()
-       GetExportedURLs() []*common.URL
-       IsExported() bool
-}
+option go_package = 
"dubbo.apache.org/dubbo-go/v3/proto/java_sql_time;java_sql_time";
+
+message Time {}
+
+message Date {}
\ No newline at end of file
diff --git a/metadata/service/exporter/exporter.go 
b/metadata/triple_api/proto/java_util/java_util.proto
similarity index 70%
copy from metadata/service/exporter/exporter.go
copy to metadata/triple_api/proto/java_util/java_util.proto
index ab4e2fedd..3228cfc07 100644
--- a/metadata/service/exporter/exporter.go
+++ b/metadata/triple_api/proto/java_util/java_util.proto
@@ -13,18 +13,14 @@
  * 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 exporter
+syntax = "proto3";
 
-import (
-       "dubbo.apache.org/dubbo-go/v3/common"
-)
+package java_util;
 
-// MetadataServiceExporter will export & unexport the metadata service,  get 
exported url, and return is exported or not
-type MetadataServiceExporter interface {
-       Export(url *common.URL) error
-       Unexport()
-       GetExportedURLs() []*common.URL
-       IsExported() bool
-}
+option go_package = "dubbo.apache.org/dubbo-go/v3/proto/java_util;java_util";
+
+message Locale {}
+
+message UUID {}
\ No newline at end of file
diff --git a/metadata/triple_api/proto/metadata_service.hessian2.go 
b/metadata/triple_api/proto/metadata_service.hessian2.go
new file mode 100644
index 000000000..2ba680acb
--- /dev/null
+++ b/metadata/triple_api/proto/metadata_service.hessian2.go
@@ -0,0 +1,127 @@
+// Code generated by protoc-gen-go-dubbo. DO NOT EDIT.
+
+// Source: metadata_service.proto
+// Package: org_apache_dubbo_metadata
+
+package triple_api
+
+import (
+       dubbo_go_hessian2 "github.com/apache/dubbo-go-hessian2"
+)
+
+type MetadataInfo struct {
+       App      string
+       Version  string
+       Services map[string]*ServiceInfo
+}
+
+func (x *MetadataInfo) JavaClassName() string {
+       return "org.apache.dubbo.metadata.MetadataInfo"
+}
+
+func (x *MetadataInfo) String() string {
+       e := dubbo_go_hessian2.NewEncoder()
+       err := e.Encode(x)
+       if err != nil {
+               return ""
+       }
+       return string(e.Buffer())
+}
+
+func (x *MetadataInfo) GetApp() string {
+       if x != nil {
+               return x.App
+       }
+       return ""
+}
+
+func (x *MetadataInfo) GetVersion() string {
+       if x != nil {
+               return x.Version
+       }
+       return ""
+}
+
+func (x *MetadataInfo) GetServices() map[string]*ServiceInfo {
+       if x != nil {
+               return x.Services
+       }
+       return nil
+}
+
+type ServiceInfo struct {
+       Name     string
+       Group    string
+       Version  string
+       Protocol string
+       Port     int32
+       Path     string
+       Params   map[string]string
+}
+
+func (x *ServiceInfo) JavaClassName() string {
+       return "org.apache.dubbo.metadata.MetadataInfo$ServiceInfo"
+}
+
+func (x *ServiceInfo) String() string {
+       e := dubbo_go_hessian2.NewEncoder()
+       err := e.Encode(x)
+       if err != nil {
+               return ""
+       }
+       return string(e.Buffer())
+}
+
+func (x *ServiceInfo) GetName() string {
+       if x != nil {
+               return x.Name
+       }
+       return ""
+}
+
+func (x *ServiceInfo) GetGroup() string {
+       if x != nil {
+               return x.Group
+       }
+       return ""
+}
+
+func (x *ServiceInfo) GetVersion() string {
+       if x != nil {
+               return x.Version
+       }
+       return ""
+}
+
+func (x *ServiceInfo) GetProtocol() string {
+       if x != nil {
+               return x.Protocol
+       }
+       return ""
+}
+
+func (x *ServiceInfo) GetPort() int32 {
+       if x != nil {
+               return x.Port
+       }
+       return 0
+}
+
+func (x *ServiceInfo) GetPath() string {
+       if x != nil {
+               return x.Path
+       }
+       return ""
+}
+
+func (x *ServiceInfo) GetParams() map[string]string {
+       if x != nil {
+               return x.Params
+       }
+       return nil
+}
+
+func init() {
+       dubbo_go_hessian2.RegisterPOJO(new(MetadataInfo))
+       dubbo_go_hessian2.RegisterPOJO(new(ServiceInfo))
+}
diff --git a/metadata/triple_api/proto/metadata_service.proto 
b/metadata/triple_api/proto/metadata_service.proto
new file mode 100644
index 000000000..1b3fb1562
--- /dev/null
+++ b/metadata/triple_api/proto/metadata_service.proto
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// The canonical version of this proto can be found at
+// https://github.com/grpc/grpc-proto/blob/master/grpc/health/v1/health.proto
+
+syntax = "proto3";
+
+package org.apache.dubbo.metadata;
+
+option go_package = "dubbo.apache.org/dubbo-go/v3/metadata/triple_api";
+
+import "hessian2_extend/hessian2_extend.proto";
+
+service MetadataService{
+  rpc GetMetadataInfo(MetadataRequest) returns (MetadataInfo){
+
+    option (hessian2_extend.method_extend) = {
+      method_name: "getMetadataInfo";
+    };
+  };
+
+  option (hessian2_extend.service_extend) = {
+    interface_name: "org.apache.dubbo.metadata.MetadataService";
+  };
+}
+
+message MetadataRequest{
+  string revision = 1;
+
+  option (hessian2_extend.message_extend) = {
+    extend_args: true;
+  };
+}
+
+message MetadataInfo{
+  string app = 1;
+  string version = 2;
+  map<string,ServiceInfo> services = 3;
+
+  option (hessian2_extend.message_extend) = {
+    java_class_name: "org.apache.dubbo.metadata.MetadataInfo";
+  };
+}
+
+message ServiceInfo{
+  string name = 1;
+  string group = 2;
+  string version = 3;
+  string protocol = 4;
+  int32 port = 5;
+  string path = 6;
+  map<string,string> params = 7;
+
+  option (hessian2_extend.message_extend) = {
+    java_class_name: "org.apache.dubbo.metadata.MetadataInfo$ServiceInfo";
+  };
+}
\ No newline at end of file
diff --git a/metadata/triple_api/proto/metadata_service_v2.pb.go 
b/metadata/triple_api/proto/metadata_service_v2.pb.go
new file mode 100644
index 000000000..817b01060
--- /dev/null
+++ b/metadata/triple_api/proto/metadata_service_v2.pb.go
@@ -0,0 +1,402 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+//     protoc-gen-go v1.31.0
+//     protoc        v4.25.3
+// source: proto/metadata_service_v2.proto
+
+package triple_api
+
+import (
+       reflect "reflect"
+       sync "sync"
+)
+
+import (
+       protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+
+       protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+)
+
+const (
+       // Verify that this generated code is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+       // Verify that runtime/protoimpl is sufficiently up-to-date.
+       _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type MetadataRequest struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Revision string `protobuf:"bytes,1,opt,name=revision,proto3" 
json:"revision,omitempty"`
+}
+
+func (x *MetadataRequest) Reset() {
+       *x = MetadataRequest{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_metadata_service_v2_proto_msgTypes[0]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *MetadataRequest) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MetadataRequest) ProtoMessage() {}
+
+func (x *MetadataRequest) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_metadata_service_v2_proto_msgTypes[0]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use MetadataRequest.ProtoReflect.Descriptor instead.
+func (*MetadataRequest) Descriptor() ([]byte, []int) {
+       return file_proto_metadata_service_v2_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *MetadataRequest) GetRevision() string {
+       if x != nil {
+               return x.Revision
+       }
+       return ""
+}
+
+type MetadataInfoV2 struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       App      string                    
`protobuf:"bytes,1,opt,name=app,proto3" json:"app,omitempty"`
+       Version  string                    
`protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
+       Services map[string]*ServiceInfoV2 
`protobuf:"bytes,3,rep,name=services,proto3" json:"services,omitempty" 
protobuf_key:"bytes,1,opt,name=key,proto3" 
protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *MetadataInfoV2) Reset() {
+       *x = MetadataInfoV2{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_metadata_service_v2_proto_msgTypes[1]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *MetadataInfoV2) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*MetadataInfoV2) ProtoMessage() {}
+
+func (x *MetadataInfoV2) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_metadata_service_v2_proto_msgTypes[1]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use MetadataInfoV2.ProtoReflect.Descriptor instead.
+func (*MetadataInfoV2) Descriptor() ([]byte, []int) {
+       return file_proto_metadata_service_v2_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *MetadataInfoV2) GetApp() string {
+       if x != nil {
+               return x.App
+       }
+       return ""
+}
+
+func (x *MetadataInfoV2) GetVersion() string {
+       if x != nil {
+               return x.Version
+       }
+       return ""
+}
+
+func (x *MetadataInfoV2) GetServices() map[string]*ServiceInfoV2 {
+       if x != nil {
+               return x.Services
+       }
+       return nil
+}
+
+type ServiceInfoV2 struct {
+       state         protoimpl.MessageState
+       sizeCache     protoimpl.SizeCache
+       unknownFields protoimpl.UnknownFields
+
+       Name     string            `protobuf:"bytes,1,opt,name=name,proto3" 
json:"name,omitempty"`
+       Group    string            `protobuf:"bytes,2,opt,name=group,proto3" 
json:"group,omitempty"`
+       Version  string            `protobuf:"bytes,3,opt,name=version,proto3" 
json:"version,omitempty"`
+       Protocol string            `protobuf:"bytes,4,opt,name=protocol,proto3" 
json:"protocol,omitempty"`
+       Port     int32             `protobuf:"varint,5,opt,name=port,proto3" 
json:"port,omitempty"`
+       Path     string            `protobuf:"bytes,6,opt,name=path,proto3" 
json:"path,omitempty"`
+       Params   map[string]string `protobuf:"bytes,7,rep,name=params,proto3" 
json:"params,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" 
protobuf_val:"bytes,2,opt,name=value,proto3"`
+}
+
+func (x *ServiceInfoV2) Reset() {
+       *x = ServiceInfoV2{}
+       if protoimpl.UnsafeEnabled {
+               mi := &file_proto_metadata_service_v2_proto_msgTypes[2]
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               ms.StoreMessageInfo(mi)
+       }
+}
+
+func (x *ServiceInfoV2) String() string {
+       return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ServiceInfoV2) ProtoMessage() {}
+
+func (x *ServiceInfoV2) ProtoReflect() protoreflect.Message {
+       mi := &file_proto_metadata_service_v2_proto_msgTypes[2]
+       if protoimpl.UnsafeEnabled && x != nil {
+               ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+               if ms.LoadMessageInfo() == nil {
+                       ms.StoreMessageInfo(mi)
+               }
+               return ms
+       }
+       return mi.MessageOf(x)
+}
+
+// Deprecated: Use ServiceInfoV2.ProtoReflect.Descriptor instead.
+func (*ServiceInfoV2) Descriptor() ([]byte, []int) {
+       return file_proto_metadata_service_v2_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *ServiceInfoV2) GetName() string {
+       if x != nil {
+               return x.Name
+       }
+       return ""
+}
+
+func (x *ServiceInfoV2) GetGroup() string {
+       if x != nil {
+               return x.Group
+       }
+       return ""
+}
+
+func (x *ServiceInfoV2) GetVersion() string {
+       if x != nil {
+               return x.Version
+       }
+       return ""
+}
+
+func (x *ServiceInfoV2) GetProtocol() string {
+       if x != nil {
+               return x.Protocol
+       }
+       return ""
+}
+
+func (x *ServiceInfoV2) GetPort() int32 {
+       if x != nil {
+               return x.Port
+       }
+       return 0
+}
+
+func (x *ServiceInfoV2) GetPath() string {
+       if x != nil {
+               return x.Path
+       }
+       return ""
+}
+
+func (x *ServiceInfoV2) GetParams() map[string]string {
+       if x != nil {
+               return x.Params
+       }
+       return nil
+}
+
+var File_proto_metadata_service_v2_proto protoreflect.FileDescriptor
+
+var file_proto_metadata_service_v2_proto_rawDesc = []byte{
+       0x0a, 0x1f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x65, 0x74, 0x61, 
0x64, 0x61, 0x74, 0x61,
+       0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x32, 0x2e, 
0x70, 0x72, 0x6f, 0x74,
+       0x6f, 0x12, 0x19, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 
0x65, 0x2e, 0x64, 0x75,
+       0x62, 0x62, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 
0x22, 0x2d, 0x0a, 0x0f,
+       0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 
0x65, 0x73, 0x74, 0x12,
+       0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 
0x01, 0x20, 0x01, 0x28,
+       0x09, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x22, 
0xf8, 0x01, 0x0a, 0x0e,
+       0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x49, 0x6e, 0x66, 0x6f, 
0x56, 0x32, 0x12, 0x10,
+       0x0a, 0x03, 0x61, 0x70, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x03, 0x61, 0x70, 0x70,
+       0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 
0x02, 0x20, 0x01, 0x28,
+       0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x53, 
0x0a, 0x08, 0x73, 0x65,
+       0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 
0x32, 0x37, 0x2e, 0x6f,
+       0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x64, 0x75, 
0x62, 0x62, 0x6f, 0x2e,
+       0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4d, 0x65, 0x74, 
0x61, 0x64, 0x61, 0x74,
+       0x61, 0x49, 0x6e, 0x66, 0x6f, 0x56, 0x32, 0x2e, 0x53, 0x65, 0x72, 0x76, 
0x69, 0x63, 0x65, 0x73,
+       0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 
0x63, 0x65, 0x73, 0x1a,
+       0x65, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x45, 
0x6e, 0x74, 0x72, 0x79,
+       0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 
0x09, 0x52, 0x03, 0x6b,
+       0x65, 0x79, 0x12, 0x3e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 
0x02, 0x20, 0x01, 0x28,
+       0x0b, 0x32, 0x28, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 
0x68, 0x65, 0x2e, 0x64,
+       0x75, 0x62, 0x62, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 
0x61, 0x2e, 0x53, 0x65,
+       0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x56, 0x32, 0x52, 
0x05, 0x76, 0x61, 0x6c,
+       0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa0, 0x02, 0x0a, 0x0d, 0x53, 
0x65, 0x72, 0x76, 0x69,
+       0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x56, 0x32, 0x12, 0x12, 0x0a, 0x04, 
0x6e, 0x61, 0x6d, 0x65,
+       0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 
0x12, 0x14, 0x0a, 0x05,
+       0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 
0x05, 0x67, 0x72, 0x6f,
+       0x75, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 
0x6e, 0x18, 0x03, 0x20,
+       0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 
0x12, 0x1a, 0x0a, 0x08,
+       0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x08,
+       0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 
0x70, 0x6f, 0x72, 0x74,
+       0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 
0x12, 0x12, 0x0a, 0x04,
+       0x70, 0x61, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 
0x70, 0x61, 0x74, 0x68,
+       0x12, 0x4c, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x07, 
0x20, 0x03, 0x28, 0x0b,
+       0x32, 0x34, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 
0x65, 0x2e, 0x64, 0x75,
+       0x62, 0x62, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 
0x2e, 0x53, 0x65, 0x72,
+       0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x56, 0x32, 0x2e, 0x50, 
0x61, 0x72, 0x61, 0x6d,
+       0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 
0x6d, 0x73, 0x1a, 0x39,
+       0x0a, 0x0b, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 
0x79, 0x12, 0x10, 0x0a,
+       0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 
0x6b, 0x65, 0x79, 0x12,
+       0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 
0x28, 0x09, 0x52, 0x05,
+       0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x32, 0x7d, 0x0a, 
0x11, 0x4d, 0x65, 0x74,
+       0x61, 0x64, 0x61, 0x74, 0x61, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 
0x56, 0x32, 0x12, 0x68,
+       0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 
0x61, 0x49, 0x6e, 0x66,
+       0x6f, 0x12, 0x2a, 0x2e, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 
0x68, 0x65, 0x2e, 0x64,
+       0x75, 0x62, 0x62, 0x6f, 0x2e, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 
0x61, 0x2e, 0x4d, 0x65,
+       0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 
0x74, 0x1a, 0x29, 0x2e,
+       0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x64, 
0x75, 0x62, 0x62, 0x6f,
+       0x2e, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x4d, 0x65, 
0x74, 0x61, 0x64, 0x61,
+       0x74, 0x61, 0x49, 0x6e, 0x66, 0x6f, 0x56, 0x32, 0x42, 0x5a, 0x0a, 0x19, 
0x6f, 0x72, 0x67, 0x2e,
+       0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x64, 0x75, 0x62, 0x62, 0x6f, 
0x2e, 0x6d, 0x65, 0x74,
+       0x61, 0x64, 0x61, 0x74, 0x61, 0x50, 0x01, 0x5a, 0x3b, 0x64, 0x75, 0x62, 
0x62, 0x6f, 0x2e, 0x61,
+       0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x64, 0x75, 
0x62, 0x62, 0x6f, 0x2d,
+       0x67, 0x6f, 0x2f, 0x76, 0x33, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 
0x74, 0x61, 0x2f, 0x74,
+       0x72, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x61, 0x70, 0x69, 0x3b, 0x74, 0x72, 
0x69, 0x70, 0x6c, 0x65,
+       0x5f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+       file_proto_metadata_service_v2_proto_rawDescOnce sync.Once
+       file_proto_metadata_service_v2_proto_rawDescData = 
file_proto_metadata_service_v2_proto_rawDesc
+)
+
+func file_proto_metadata_service_v2_proto_rawDescGZIP() []byte {
+       file_proto_metadata_service_v2_proto_rawDescOnce.Do(func() {
+               file_proto_metadata_service_v2_proto_rawDescData = 
protoimpl.X.CompressGZIP(file_proto_metadata_service_v2_proto_rawDescData)
+       })
+       return file_proto_metadata_service_v2_proto_rawDescData
+}
+
+var file_proto_metadata_service_v2_proto_msgTypes = 
make([]protoimpl.MessageInfo, 5)
+var file_proto_metadata_service_v2_proto_goTypes = []interface{}{
+       (*MetadataRequest)(nil), // 0: org.apache.dubbo.metadata.MetadataRequest
+       (*MetadataInfoV2)(nil),  // 1: org.apache.dubbo.metadata.MetadataInfoV2
+       (*ServiceInfoV2)(nil),   // 2: org.apache.dubbo.metadata.ServiceInfoV2
+       nil,                     // 3: 
org.apache.dubbo.metadata.MetadataInfoV2.ServicesEntry
+       nil,                     // 4: 
org.apache.dubbo.metadata.ServiceInfoV2.ParamsEntry
+}
+var file_proto_metadata_service_v2_proto_depIdxs = []int32{
+       3, // 0: org.apache.dubbo.metadata.MetadataInfoV2.services:type_name -> 
org.apache.dubbo.metadata.MetadataInfoV2.ServicesEntry
+       4, // 1: org.apache.dubbo.metadata.ServiceInfoV2.params:type_name -> 
org.apache.dubbo.metadata.ServiceInfoV2.ParamsEntry
+       2, // 2: 
org.apache.dubbo.metadata.MetadataInfoV2.ServicesEntry.value:type_name -> 
org.apache.dubbo.metadata.ServiceInfoV2
+       0, // 3: 
org.apache.dubbo.metadata.MetadataServiceV2.GetMetadataInfo:input_type -> 
org.apache.dubbo.metadata.MetadataRequest
+       1, // 4: 
org.apache.dubbo.metadata.MetadataServiceV2.GetMetadataInfo:output_type -> 
org.apache.dubbo.metadata.MetadataInfoV2
+       4, // [4:5] is the sub-list for method output_type
+       3, // [3:4] is the sub-list for method input_type
+       3, // [3:3] is the sub-list for extension type_name
+       3, // [3:3] is the sub-list for extension extendee
+       0, // [0:3] is the sub-list for field type_name
+}
+
+func init() { file_proto_metadata_service_v2_proto_init() }
+func file_proto_metadata_service_v2_proto_init() {
+       if File_proto_metadata_service_v2_proto != nil {
+               return
+       }
+       if !protoimpl.UnsafeEnabled {
+               file_proto_metadata_service_v2_proto_msgTypes[0].Exporter = 
func(v interface{}, i int) interface{} {
+                       switch v := v.(*MetadataRequest); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_proto_metadata_service_v2_proto_msgTypes[1].Exporter = 
func(v interface{}, i int) interface{} {
+                       switch v := v.(*MetadataInfoV2); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+               file_proto_metadata_service_v2_proto_msgTypes[2].Exporter = 
func(v interface{}, i int) interface{} {
+                       switch v := v.(*ServiceInfoV2); i {
+                       case 0:
+                               return &v.state
+                       case 1:
+                               return &v.sizeCache
+                       case 2:
+                               return &v.unknownFields
+                       default:
+                               return nil
+                       }
+               }
+       }
+       type x struct{}
+       out := protoimpl.TypeBuilder{
+               File: protoimpl.DescBuilder{
+                       GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+                       RawDescriptor: 
file_proto_metadata_service_v2_proto_rawDesc,
+                       NumEnums:      0,
+                       NumMessages:   5,
+                       NumExtensions: 0,
+                       NumServices:   1,
+               },
+               GoTypes:           file_proto_metadata_service_v2_proto_goTypes,
+               DependencyIndexes: file_proto_metadata_service_v2_proto_depIdxs,
+               MessageInfos:      
file_proto_metadata_service_v2_proto_msgTypes,
+       }.Build()
+       File_proto_metadata_service_v2_proto = out.File
+       file_proto_metadata_service_v2_proto_rawDesc = nil
+       file_proto_metadata_service_v2_proto_goTypes = nil
+       file_proto_metadata_service_v2_proto_depIdxs = nil
+}
diff --git a/metadata/service/exporter/exporter.go 
b/metadata/triple_api/proto/metadata_service_v2.proto
similarity index 54%
copy from metadata/service/exporter/exporter.go
copy to metadata/triple_api/proto/metadata_service_v2.proto
index ab4e2fedd..77c49d102 100644
--- a/metadata/service/exporter/exporter.go
+++ b/metadata/triple_api/proto/metadata_service_v2.proto
@@ -15,16 +15,33 @@
  * limitations under the License.
  */
 
-package exporter
+syntax = "proto3";
+package org.apache.dubbo.metadata;
 
-import (
-       "dubbo.apache.org/dubbo-go/v3/common"
-)
+option go_package = 
"dubbo.apache.org/dubbo-go/v3/metadata/triple_api;triple_api";
+option java_package = "org.apache.dubbo.metadata";
+option java_multiple_files = true;
 
-// MetadataServiceExporter will export & unexport the metadata service,  get 
exported url, and return is exported or not
-type MetadataServiceExporter interface {
-       Export(url *common.URL) error
-       Unexport()
-       GetExportedURLs() []*common.URL
-       IsExported() bool
+service MetadataServiceV2{
+    rpc GetMetadataInfo(MetadataRequest) returns (MetadataInfoV2);
+}
+
+message MetadataRequest{
+    string revision = 1;
+}
+
+message MetadataInfoV2{
+    string app = 1;
+    string version = 2;
+    map<string,ServiceInfoV2> services = 3;
+}
+
+message ServiceInfoV2{
+    string name = 1;
+    string group = 2;
+    string version = 3;
+    string protocol = 4;
+    int32 port = 5;
+    string path = 6;
+    map<string,string> params = 7;
 }
diff --git a/metadata/triple_api/proto/self_extension/self_extension.proto 
b/metadata/triple_api/proto/self_extension/self_extension.proto
new file mode 100644
index 000000000..03f600dba
--- /dev/null
+++ b/metadata/triple_api/proto/self_extension/self_extension.proto
@@ -0,0 +1,15 @@
+syntax = "proto3";
+
+package self_extension;
+
+option go_package = 
"github.com/apache/dubbo-go-samples/java_interop/non-protobuf-triple/proto/self_extension;self_extension";
+
+import "google/protobuf/descriptor.proto";
+import "hessian2_extend/hessian2_extend.proto";
+
+message Time {
+  option (hessian2_extend.message_extend) = {
+    java_class_name: "java.sql.Time";
+    reference_path: "dubbo.apache.org/dubbo-go/v3/proto/java_sql_time";
+  };
+}
\ No newline at end of file
diff --git a/options.go b/options.go
index fb1d27005..d450e4f77 100644
--- a/options.go
+++ b/options.go
@@ -17,6 +17,10 @@
 
 package dubbo
 
+import (
+       "strconv"
+)
+
 import (
        log "github.com/dubbogo/gost/log/logger"
 )
@@ -330,6 +334,18 @@ func WithTag(tag string) InstanceOption {
        }
 }
 
+func WithMetadataServicePort(port int) InstanceOption {
+       return func(insOpts *InstanceOptions) {
+               insOpts.Application.MetadataServicePort = strconv.Itoa(port)
+       }
+}
+
+func WithMetadataServiceProtocol(protocol string) InstanceOption {
+       return func(insOpts *InstanceOptions) {
+               insOpts.Application.MetadataServiceProtocol = protocol
+       }
+}
+
 func WithProtocol(opts ...protocol.Option) InstanceOption {
        proOpts := protocol.NewOptions(opts...)
 
diff --git a/protocol/triple/triple.go b/protocol/triple/triple.go
index 9ee503ff9..343887b3a 100644
--- a/protocol/triple/triple.go
+++ b/protocol/triple/triple.go
@@ -18,6 +18,7 @@
 package triple
 
 import (
+       "context"
        "sync"
 )
 
@@ -151,3 +152,19 @@ func GetProtocol() protocol.Protocol {
        }
        return tripleProtocol
 }
+
+type ServiceInfo struct {
+       InterfaceName string
+       ServiceType   interface{}
+       Methods       []MethodInfo
+       Meta          map[string]interface{}
+}
+
+type MethodInfo struct {
+       Name           string
+       Type           string
+       ReqInitFunc    func() interface{}
+       StreamInitFunc func(baseStream interface{}) interface{}
+       MethodFunc     func(ctx context.Context, args []interface{}, handler 
interface{}) (interface{}, error)
+       Meta           map[string]interface{}
+}
diff --git a/protocol/triple/triple_protocol/envelope.go 
b/protocol/triple/triple_protocol/envelope.go
index 000f08dc8..11db23435 100644
--- a/protocol/triple/triple_protocol/envelope.go
+++ b/protocol/triple/triple_protocol/envelope.go
@@ -76,7 +76,7 @@ func (w *envelopeWriter) Marshal(message interface{}) *Error {
        raw, err := w.codec.Marshal(message)
        if err != nil {
                if w.backupCodec != nil && w.codec.Name() != 
w.backupCodec.Name() {
-                       logger.Warnf("failed to marshal message with codec %s, 
trying alternative codec %s", w.codec.Name(), w.backupCodec.Name())
+                       logger.Debugf("failed to marshal message with codec %s, 
trying alternative codec %s", w.codec.Name(), w.backupCodec.Name())
                        raw, err = w.backupCodec.Marshal(message)
                }
                if err != nil {
@@ -202,7 +202,7 @@ func (r *envelopeReader) Unmarshal(message interface{}) 
*Error {
 
        if err := r.codec.Unmarshal(data.Bytes(), message); err != nil {
                if r.backupCodec != nil && r.backupCodec.Name() != 
r.codec.Name() {
-                       logger.Warnf("failed to unmarshal message with codec 
%s, trying alternative codec %s", r.codec.Name(), r.backupCodec.Name())
+                       logger.Debugf("failed to unmarshal message with codec 
%s, trying alternative codec %s", r.codec.Name(), r.backupCodec.Name())
                        err = r.backupCodec.Unmarshal(data.Bytes(), message)
                }
                if err != nil {
diff --git a/common/extension/metadata_service_exporter.go 
b/registry/event/metadata_service_version_customizer.go
similarity index 50%
copy from common/extension/metadata_service_exporter.go
copy to registry/event/metadata_service_version_customizer.go
index ab8cff8f4..8c476c917 100644
--- a/common/extension/metadata_service_exporter.go
+++ b/registry/event/metadata_service_version_customizer.go
@@ -15,32 +15,28 @@
  * limitations under the License.
  */
 
-package extension
+package event
 
 import (
        "dubbo.apache.org/dubbo-go/v3/common/constant"
-       "dubbo.apache.org/dubbo-go/v3/metadata/service"
-       "dubbo.apache.org/dubbo-go/v3/metadata/service/exporter"
+       "dubbo.apache.org/dubbo-go/v3/common/extension"
+       "dubbo.apache.org/dubbo-go/v3/registry"
 )
 
-type MetadataServiceExporterCreator func(service.MetadataService) 
exporter.MetadataServiceExporter
+func init() {
+       extension.AddCustomizers(&MetadtaServiceVersionCustomizer{})
+}
 
-var (
-       metadataServiceExporterInsMap = 
make(map[string]MetadataServiceExporterCreator, 2)
-)
+// MetadtaServiceVersionCustomizer will try to add meta-v key to instance 
metadata
+type MetadtaServiceVersionCustomizer struct {
+}
 
-// SetMetadataServiceExporter will store the type => creator pair
-func SetMetadataServiceExporter(key string, creator 
MetadataServiceExporterCreator) {
-       metadataServiceExporterInsMap[key] = creator
+// GetPriority will return 0, which means it will be invoked at the beginning
+func (p *MetadtaServiceVersionCustomizer) GetPriority() int {
+       return 0
 }
 
-// GetMetadataServiceExporter will create a MetadataServiceExporter instance
-func GetMetadataServiceExporter(key string, s service.MetadataService) 
exporter.MetadataServiceExporter {
-       if key == "" {
-               key = constant.DefaultKey
-       }
-       if creator, ok := metadataServiceExporterInsMap[key]; ok {
-               return creator(s)
-       }
-       return nil
+// Customize put the the string like [{"protocol": "dubbo", "port": 123}] into 
instance's metadata
+func (p *MetadtaServiceVersionCustomizer) Customize(instance 
registry.ServiceInstance) {
+       instance.GetMetadata()[constant.MetadataVersion] = 
constant.MetadataServiceV2Version
 }
diff --git a/registry/exposed_tmp/exposed.go b/registry/exposed_tmp/exposed.go
index f6861e068..6f98fffdf 100644
--- a/registry/exposed_tmp/exposed.go
+++ b/registry/exposed_tmp/exposed.go
@@ -128,5 +128,12 @@ func selectMetadataServiceExportedURL() *common.URL {
                        break
                }
        }
+       for _, url := range urlList {
+               selectedUrl = url
+               // triple first
+               if url.Protocol == constant.TriProtocol {
+                       break
+               }
+       }
        return selectedUrl
 }
diff --git a/registry/servicediscovery/service_discovery_registry.go 
b/registry/servicediscovery/service_discovery_registry.go
index f2ad8fadf..2bbdb0ad9 100644
--- a/registry/servicediscovery/service_discovery_registry.go
+++ b/registry/servicediscovery/service_discovery_registry.go
@@ -233,7 +233,7 @@ func (s *ServiceDiscoveryRegistry) SubscribeURL(url 
*common.URL, notify registry
        // FIXME ServiceNames.String() is not good
        var err error
        serviceNamesKey := services.String()
-       protocol := "tri" // consume "tri" protocol by default, other protocols 
need to be specified on reference/consumer explicitly
+       protocol := constant.TriProtocol // consume "tri" protocol by default, 
other protocols need to be specified on reference/consumer explicitly
        if url.Protocol != "" {
                protocol = url.Protocol
        }
diff --git 
a/registry/servicediscovery/service_instances_changed_listener_impl.go 
b/registry/servicediscovery/service_instances_changed_listener_impl.go
index e0e7d2189..11a175379 100644
--- a/registry/servicediscovery/service_instances_changed_listener_impl.go
+++ b/registry/servicediscovery/service_instances_changed_listener_impl.go
@@ -18,6 +18,7 @@
 package servicediscovery
 
 import (
+       "context"
        "encoding/gob"
        "errors"
        "reflect"
@@ -37,6 +38,7 @@ import (
        "dubbo.apache.org/dubbo-go/v3/common/extension"
        "dubbo.apache.org/dubbo-go/v3/metadata/service"
        "dubbo.apache.org/dubbo-go/v3/metadata/service/local"
+       triple_api "dubbo.apache.org/dubbo-go/v3/metadata/triple_api/proto"
        "dubbo.apache.org/dubbo-go/v3/registry"
        "dubbo.apache.org/dubbo-go/v3/registry/servicediscovery/store"
        "dubbo.apache.org/dubbo-go/v3/remoting"
@@ -242,13 +244,29 @@ func GetMetadataInfo(app string, instance 
registry.ServiceInstance, revision str
                        err = remoteMetadataErr
                }
        } else {
-               proxyFactory := 
extension.GetMetadataServiceProxyFactory(constant.DefaultKey)
-               metadataService := proxyFactory.GetProxy(instance)
-               if metadataService != nil {
-                       defer destroyInvoker(metadataService)
-                       metadataInfo, err = 
metadataService.GetMetadataInfo(revision)
+               if instance.GetMetadata()[constant.MetadataVersion] == 
constant.MetadataServiceV2Version {
+                       proxyFactoryV2 := 
extension.GetMetadataServiceProxyFactoryV2(constant.MetadataServiceV2)
+                       metadataServiceV2 := proxyFactoryV2.GetProxy(instance)
+                       if metadataServiceV2 != nil {
+                               defer destroyInvokerV2(metadataServiceV2)
+                               var metadataInfoV2 *triple_api.MetadataInfoV2
+                               metadataInfoV2, err = 
metadataServiceV2.GetMetadataInfo(context.Background(), 
&triple_api.MetadataRequest{Revision: revision})
+                               if err != nil {
+                                       logger.Errorf("get metadata of %s 
failed, %v", instance.GetHost(), err)
+                               }
+                               metadataInfo = 
convertMetadataInfo(metadataInfoV2)
+                       } else {
+                               err = errors.New("get remote metadata error 
please check instance " + instance.GetHost() + " is alive")
+                       }
                } else {
-                       err = errors.New("get remote metadata error please 
check instance " + instance.GetHost() + " is alive")
+                       proxyFactory := 
extension.GetMetadataServiceProxyFactory(constant.DefaultKey)
+                       metadataService := proxyFactory.GetProxy(instance)
+                       if metadataService != nil {
+                               defer destroyInvoker(metadataService)
+                               metadataInfo, err = 
metadataService.GetMetadataInfo(revision)
+                       } else {
+                               err = errors.New("get remote metadata error 
please check instance " + instance.GetHost() + " is alive")
+                       }
                }
        }
 
@@ -263,6 +281,29 @@ func GetMetadataInfo(app string, instance 
registry.ServiceInstance, revision str
        return metadataInfo
 }
 
+func convertMetadataInfo(v2 *triple_api.MetadataInfoV2) *common.MetadataInfo {
+       infos := make(map[string]*common.ServiceInfo, 0)
+       for k, v := range v2.Services {
+               info := &common.ServiceInfo{
+                       Name:     v.Name,
+                       Group:    v.Group,
+                       Version:  v.Version,
+                       Protocol: v.Protocol,
+                       Path:     v.Path,
+                       Params:   v.Params,
+               }
+               infos[k] = info
+       }
+
+       metadataInfo := &common.MetadataInfo{
+               Reported: false,
+               App:      v2.App,
+               Revision: v2.Version,
+               Services: infos,
+       }
+       return metadataInfo
+}
+
 func destroyInvoker(metadataService service.MetadataService) {
        if metadataService == nil {
                return
@@ -275,3 +316,16 @@ func destroyInvoker(metadataService 
service.MetadataService) {
 
        proxy.Invoker.Destroy()
 }
+
+func destroyInvokerV2(metadataService service.MetadataServiceV2) {
+       if metadataService == nil {
+               return
+       }
+
+       proxy := metadataService.(*local.MetadataServiceProxyV2)
+       if proxy.Invoker == nil {
+               return
+       }
+
+       proxy.Invoker.Destroy()
+}
diff --git a/server/action.go b/server/action.go
index 98a40ec61..39f63e750 100644
--- a/server/action.go
+++ b/server/action.go
@@ -233,16 +233,6 @@ func (svcOpts *ServiceOptions) export(info *ServiceInfo) 
error {
                                svcOpts.exporters = append(svcOpts.exporters, 
exporter)
                        }
                } else {
-                       if ivkURL.GetParam(constant.InterfaceKey, "") == 
constant.MetadataServiceName {
-                               ms, err := extension.GetLocalMetadataService("")
-                               if err != nil {
-                                       logger.Warnf("needExport 
org.apache.dubbo.metadata.MetadataService failed beacause of %svcOpts ! pls 
check if you import _ \"dubbo.apache.org/dubbo-go/v3/metadata/service/local\"", 
err)
-                                       return nil
-                               }
-                               if err := ms.SetMetadataServiceURL(ivkURL); err 
!= nil {
-                                       logger.Warnf("SetMetadataServiceURL 
error = %svcOpts", err)
-                               }
-                       }
                        invoker = svcOpts.generatorInvoker(ivkURL, info)
                        exporter := 
extension.GetProtocol(protocolwrapper.FILTER).Export(invoker)
                        if exporter == nil {
diff --git a/server/compat.go b/server/compat.go
index d5b02ed16..46f9fcf00 100644
--- a/server/compat.go
+++ b/server/compat.go
@@ -29,15 +29,17 @@ import (
 // todo(DMwangnima): remove these functions when refactoring dubbo-go
 func compatApplicationConfig(c *global.ApplicationConfig) 
*config.ApplicationConfig {
        return &config.ApplicationConfig{
-               Organization: c.Organization,
-               Name:         c.Name,
-               Module:       c.Module,
-               Group:        c.Group,
-               Version:      c.Version,
-               Owner:        c.Owner,
-               Environment:  c.Environment,
-               MetadataType: c.MetadataType,
-               Tag:          c.Tag,
+               Organization:            c.Organization,
+               Name:                    c.Name,
+               Module:                  c.Module,
+               Group:                   c.Group,
+               Version:                 c.Version,
+               Owner:                   c.Owner,
+               Environment:             c.Environment,
+               MetadataType:            c.MetadataType,
+               Tag:                     c.Tag,
+               MetadataServicePort:     c.MetadataServicePort,
+               MetadataServiceProtocol: c.MetadataServiceProtocol,
        }
 }
 
diff --git a/server/metadata.go b/server/metadata.go
new file mode 100644
index 000000000..ae2c40491
--- /dev/null
+++ b/server/metadata.go
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package server
+
+import (
+       "context"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       triple_api "dubbo.apache.org/dubbo-go/v3/metadata/triple_api/proto"
+       "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
+)
+
+// MetadataServiceV2Handler is an implementation of the 
org.apache.dubbo.metadata.MetadataServiceV2 service.
+type MetadataServiceV2Handler interface {
+       GetMetadataInfo(context.Context, *triple_api.MetadataRequest) 
(*triple_api.MetadataInfoV2, error)
+}
+
+var MetadataServiceV2_ServiceInfo = ServiceInfo{
+       InterfaceName: "org.apache.dubbo.metadata.MetadataServiceV2",
+       ServiceType:   (*MetadataServiceV2Handler)(nil),
+       Methods: []MethodInfo{
+               {
+                       Name: "GetMetadataInfo",
+                       Type: constant.CallUnary,
+                       ReqInitFunc: func() interface{} {
+                               return new(triple_api.MetadataRequest)
+                       },
+                       MethodFunc: func(ctx context.Context, args 
[]interface{}, handler interface{}) (interface{}, error) {
+                               req := args[0].(*triple_api.MetadataRequest)
+                               res, err := 
handler.(MetadataServiceV2Handler).GetMetadataInfo(ctx, req)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               return triple_protocol.NewResponse(res), nil
+                       },
+               },
+               {
+                       Name: "getMetadataInfo",
+                       Type: constant.CallUnary,
+                       ReqInitFunc: func() interface{} {
+                               return new(triple_api.MetadataRequest)
+                       },
+                       MethodFunc: func(ctx context.Context, args 
[]interface{}, handler interface{}) (interface{}, error) {
+                               req := args[0].(*triple_api.MetadataRequest)
+                               res, err := 
handler.(MetadataServiceV2Handler).GetMetadataInfo(ctx, req)
+                               if err != nil {
+                                       return nil, err
+                               }
+                               return triple_protocol.NewResponse(res), nil
+                       },
+               },
+       },
+}
+
+type MetadataServiceHandler interface {
+       GetMetadataInfo(ctx context.Context, revision string) 
(*triple_api.MetadataInfo, error)
+}
+
+var MetadataService_ServiceInfo = ServiceInfo{
+       InterfaceName: "org.apache.dubbo.metadata.MetadataService",
+       ServiceType:   (*MetadataServiceHandler)(nil),
+       Methods: []MethodInfo{
+               {
+                       Name: "getMetadataInfo",
+                       Type: constant.CallUnary,
+                       ReqInitFunc: func() interface{} {
+                               return new(string)
+                       },
+                       MethodFunc: func(ctx context.Context, args 
[]interface{}, handler interface{}) (interface{}, error) {
+                               revision := args[0].(*string)
+                               res, err := 
handler.(MetadataServiceHandler).GetMetadataInfo(ctx, *revision)
+                               return res, err
+                       },
+               },
+       },
+}
diff --git a/server/server.go b/server/server.go
index 5d9281ed9..f983a627f 100644
--- a/server/server.go
+++ b/server/server.go
@@ -20,7 +20,6 @@ package server
 
 import (
        "context"
-       "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
        "fmt"
        "sort"
        "sync"
@@ -37,6 +36,7 @@ import (
        dubboutil "dubbo.apache.org/dubbo-go/v3/common/dubboutil"
        "dubbo.apache.org/dubbo-go/v3/metadata"
        "dubbo.apache.org/dubbo-go/v3/protocol"
+       "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
        registry_exposed "dubbo.apache.org/dubbo-go/v3/registry/exposed_tmp"
 )
 
@@ -108,7 +108,13 @@ func (ii *infoInvoker) Invoke(ctx context.Context, 
invocation protocol.Invocatio
                res, err := method.MethodFunc(ctx, args, ii.svc)
                result.SetResult(res)
                if err != nil {
-                       
result.SetError(triple_protocol.NewError(triple_protocol.CodeBizError, err))
+                       var proError *triple_protocol.Error
+                       if !errors.As(err, &proError) {
+                               err = 
triple_protocol.NewError(triple_protocol.CodeBizError, err)
+                       } else if proError.Code() != 
triple_protocol.CodeBizError {
+                               err = triple_protocol.NewError(proError.Code(), 
proError.Unwrap())
+                       }
+                       result.SetError(err)
                }
                return result
        }
@@ -127,6 +133,10 @@ func newInfoInvoker(url *common.URL, info *ServiceInfo, 
svc common.RPCService) p
        return invoker
 }
 
+func NewInternalInvoker(url *common.URL, info *ServiceInfo, svc 
common.RPCService) protocol.Invoker {
+       return newInfoInvoker(url, info, svc)
+}
+
 // Register assemble invoker chains like ProviderConfig.Load, init a service 
per call
 func (s *Server) Register(handler interface{}, info *ServiceInfo, opts 
...ServiceOption) error {
        newSvcOpts, err := s.genSvcOpts(handler, opts...)

Reply via email to