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

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


The following commit(s) were added to refs/heads/feature-triple by this push:
     new 8682a2e2a feat: finish server layer (#2425)
8682a2e2a is described below

commit 8682a2e2a3a8903ddc224e724a8fe4a9e25740f7
Author: Scout Wang <[email protected]>
AuthorDate: Wed Oct 11 15:11:43 2023 +0800

    feat: finish server layer (#2425)
---
 client/action.go                                   |   4 +
 client/options.go                                  | 224 ++++++---
 common/constant/key.go                             |   1 +
 common/constant/serialization.go                   |   1 +
 common/url.go                                      |  25 +-
 compat.go                                          | 124 +++++
 dubbo.go                                           | 112 +++--
 global/profiles_config.go                          |   2 +-
 global/protocol_config.go                          |   8 +-
 global/provider_config.go                          |  11 +-
 global/reference_config.go                         |  12 +-
 global/registry_config.go                          |   4 +
 global/service_config.go                           |  34 +-
 global/tls_config.go                               |   1 +
 graceful_shutdown/common.go                        |  17 +-
 graceful_shutdown/compat.go                        |   5 +-
 graceful_shutdown/options.go                       |  62 ++-
 graceful_shutdown/shutdown.go                      |  19 +-
 loader.go                                          | 347 ++++++++++++++
 metadata/metadata.go                               |  86 ++++
 metadata/service/local/service.go                  |   1 +
 options.go                                         | 344 +++++++++-----
 protocol/dubbo3/dubbo3_protocol.go                 |   4 +-
 protocol/options.go                                |  96 ++++
 protocol/triple/client.go                          |  47 +-
 .../triple/internal/client/cmd_classic/dubbogo.yml |  11 -
 .../triple/internal/client/cmd_classic/main.go     |  28 --
 protocol/triple/internal/client/cmd_client/main.go |  34 +-
 .../cmd_client_with_registry}/main.go              |  20 +-
 .../triple/internal/client/cmd_instance/main.go    |  47 +-
 .../cmd_instance_with_registry}/main.go            |  30 +-
 protocol/triple/internal/client/common/client.go   | 119 +++++
 .../triple/internal/dubbo3_server/cmd/dubbogo.yml  |  13 +
 protocol/triple/internal/dubbo3_server/cmd/main.go |  15 +
 .../proto/triple_gen/greettriple/greet.triple.go   |  11 +-
 protocol/triple/internal/server/cmd/dubbogo.yml    |  16 -
 .../internal/server/{cmd => cmd_instance}/main.go  |  18 +-
 .../{cmd => cmd_instance_with_registry}/main.go    |  23 +-
 .../internal/server/{cmd => cmd_server}/main.go    |  12 +-
 .../{cmd => cmd_server_with_registry}/main.go      |  17 +-
 protocol/triple/server.go                          |  41 +-
 .../triple/triple-tool/gen/generator/genTriple.go  |   1 +
 protocol/triple/triple.go                          |  10 +-
 registry/exposed_tmp/exposed.go                    | 132 ++++++
 registry/options.go                                | 165 +++++++
 server/action.go                                   | 244 +++++-----
 server/compat.go                                   |  11 +
 server/options.go                                  | 504 ++++++++++++++++++---
 server/server.go                                   | 121 ++++-
 49 files changed, 2632 insertions(+), 602 deletions(-)

diff --git a/client/action.go b/client/action.go
index d20fd9d1d..58893e561 100644
--- a/client/action.go
+++ b/client/action.go
@@ -39,6 +39,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"
+       "dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
        "dubbo.apache.org/dubbo-go/v3/protocol"
        "dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper"
        "dubbo.apache.org/dubbo-go/v3/proxy"
@@ -252,6 +253,9 @@ func (opts *ClientOptions) refer(srv common.RPCService, 
info *ClientInfo) {
                }
                opts.pxy.Implement(srv)
        }
+       // this protocol would be destroyed in graceful_shutdown
+       // please refer to (https://github.com/apache/dubbo-go/issues/2429)
+       graceful_shutdown.RegisterProtocol(ref.Protocol)
 }
 
 func (opts *ClientOptions) CheckAvailable() bool {
diff --git a/client/options.go b/client/options.go
index 3f6169f4f..c5e176031 100644
--- a/client/options.go
+++ b/client/options.go
@@ -19,6 +19,7 @@ package client
 
 import (
        "strconv"
+       "time"
 )
 
 import (
@@ -28,10 +29,13 @@ import (
 import (
        "dubbo.apache.org/dubbo-go/v3/common"
        commonCfg "dubbo.apache.org/dubbo-go/v3/common/config"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
        "dubbo.apache.org/dubbo-go/v3/config"
        "dubbo.apache.org/dubbo-go/v3/global"
+       "dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
        "dubbo.apache.org/dubbo-go/v3/protocol"
        "dubbo.apache.org/dubbo-go/v3/proxy"
+       "dubbo.apache.org/dubbo-go/v3/registry"
 )
 
 type ClientOptions struct {
@@ -39,6 +43,7 @@ type ClientOptions struct {
        Consumer    *global.ConsumerConfig
        Reference   *global.ReferenceConfig
        Registries  map[string]*global.RegistryConfig
+       Shutdown    *global.ShutdownConfig
 
        pxy          *proxy.Proxy
        id           string
@@ -54,7 +59,10 @@ type ClientOptions struct {
 
 func defaultClientOptions() *ClientOptions {
        return &ClientOptions{
-               Reference: global.DefaultReferenceConfig(),
+               Application: global.DefaultApplicationConfig(),
+               Consumer:    global.DefaultConsumerConfig(),
+               Reference:   global.DefaultReferenceConfig(),
+               Shutdown:    global.DefaultShutdownConfig(),
        }
 }
 
@@ -103,6 +111,10 @@ func (cliOpts *ClientOptions) init(opts ...ClientOption) 
error {
 
        // todo(DMwangnima): move to registry package
        // init registries
+       var emptyRegIDsFlag bool
+       if ref.RegistryIDs == nil || len(ref.RegistryIDs) <= 0 {
+               emptyRegIDsFlag = true
+       }
        regs := cliOpts.Registries
        if regs != nil {
                cliOpts.registriesCompat = 
make(map[string]*config.RegistryConfig)
@@ -111,10 +123,16 @@ func (cliOpts *ClientOptions) init(opts ...ClientOption) 
error {
                        if err := cliOpts.registriesCompat[key].Init(); err != 
nil {
                                return err
                        }
+                       if emptyRegIDsFlag {
+                               ref.RegistryIDs = append(ref.RegistryIDs, key)
+                       }
                }
        }
        ref.RegistryIDs = commonCfg.TranslateIds(ref.RegistryIDs)
 
+       // init graceful_shutdown
+       
graceful_shutdown.Init(graceful_shutdown.WithShutdown_Config(cliOpts.Shutdown))
+
        return commonCfg.Verify(cliOpts)
 }
 
@@ -122,8 +140,9 @@ type ClientOption func(*ClientOptions)
 
 // ---------- For user ----------
 
-func WithCheck(check bool) ClientOption {
+func WithCheck() ClientOption {
        return func(opts *ClientOptions) {
+               check := true
                opts.Reference.Check = &check
        }
 }
@@ -134,18 +153,14 @@ func WithURL(url string) ClientOption {
        }
 }
 
+// todo(DMwangnima): change Filter Option like Cluster and LoadBalance
 func WithFilter(filter string) ClientOption {
        return func(opts *ClientOptions) {
                opts.Reference.Filter = filter
        }
 }
 
-func WithProtocol(protocol string) ClientOption {
-       return func(opts *ClientOptions) {
-               opts.Reference.Protocol = protocol
-       }
-}
-
+// todo(DMwangnima): think about a more ideal configuration style
 func WithRegistryIDs(registryIDs []string) ClientOption {
        return func(opts *ClientOptions) {
                if len(registryIDs) > 0 {
@@ -154,15 +169,122 @@ func WithRegistryIDs(registryIDs []string) ClientOption {
        }
 }
 
-func WithCluster(cluster string) ClientOption {
+func WithRegistry(key string, opts ...registry.Option) ClientOption {
+       regOpts := registry.DefaultOptions()
+       for _, opt := range opts {
+               opt(regOpts)
+       }
+
+       return func(cliOpts *ClientOptions) {
+               if cliOpts.Registries == nil {
+                       cliOpts.Registries = 
make(map[string]*global.RegistryConfig)
+               }
+               cliOpts.Registries[key] = regOpts.Registry
+       }
+}
+
+func WithShutdown(opts ...graceful_shutdown.Option) ClientOption {
+       sdOpts := graceful_shutdown.DefaultOptions()
+       for _, opt := range opts {
+               opt(sdOpts)
+       }
+
+       return func(cliOpts *ClientOptions) {
+               cliOpts.Shutdown = sdOpts.Shutdown
+       }
+}
+
+// ========== Cluster Strategy ==========
+
+func WithClusterAvailable() ClientOption {
        return func(opts *ClientOptions) {
-               opts.Reference.Cluster = cluster
+               opts.Reference.Cluster = constant.ClusterKeyAvailable
        }
 }
 
-func WithLoadBalance(loadBalance string) ClientOption {
+func WithClusterBroadcast() ClientOption {
        return func(opts *ClientOptions) {
-               opts.Reference.Loadbalance = loadBalance
+               opts.Reference.Cluster = constant.ClusterKeyBroadcast
+       }
+}
+
+func WithClusterFailBack() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Cluster = constant.ClusterKeyFailback
+       }
+}
+
+func WithClusterFailFast() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Cluster = constant.ClusterKeyFailfast
+       }
+}
+
+func WithClusterFailOver() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Cluster = constant.ClusterKeyFailover
+       }
+}
+
+func WithClusterFailSafe() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Cluster = constant.ClusterKeyFailsafe
+       }
+}
+
+func WithClusterForking() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Cluster = constant.ClusterKeyForking
+       }
+}
+
+func WithClusterZoneAware() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Cluster = constant.ClusterKeyZoneAware
+       }
+}
+
+func WithClusterAdaptiveService() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Cluster = constant.ClusterKeyAdaptiveService
+       }
+}
+
+// ========== LoadBalance Strategy ==========
+
+func WithLoadBalanceConsistentHashing() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Loadbalance = 
constant.LoadBalanceKeyConsistentHashing
+       }
+}
+
+func WithLoadBalanceLeastActive() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Loadbalance = constant.LoadBalanceKeyLeastActive
+       }
+}
+
+func WithLoadBalanceRandom() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Loadbalance = constant.LoadBalanceKeyRandom
+       }
+}
+
+func WithLoadBalanceRoundRobin() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Loadbalance = constant.LoadBalanceKeyRoundRobin
+       }
+}
+
+func WithLoadBalanceP2C() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Loadbalance = constant.LoadBalanceKeyP2C
+       }
+}
+
+func WithLoadBalanceXDSRingHash() ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference.Loadbalance = constant.LoadBalanceKeyLeastActive
        }
 }
 
@@ -184,23 +306,24 @@ func WithVersion(version string) ClientOption {
        }
 }
 
-func WithSerialization(serialization string) ClientOption {
+func WithJSON() ClientOption {
        return func(opts *ClientOptions) {
-               opts.Reference.Serialization = serialization
+               opts.Reference.Serialization = constant.JSONSerialization
        }
 }
 
-func WithProviderBy(providedBy string) ClientOption {
+func WithProvidedBy(providedBy string) ClientOption {
        return func(opts *ClientOptions) {
                opts.Reference.ProvidedBy = providedBy
        }
 }
 
-func WithAsync(async bool) ClientOption {
-       return func(opts *ClientOptions) {
-               opts.Reference.Async = async
-       }
-}
+// todo(DMwangnima): implement this functionality
+//func WithAsync() ClientOption {
+//     return func(opts *ClientOptions) {
+//             opts.Reference.Async = true
+//     }
+//}
 
 func WithParams(params map[string]string) ClientOption {
        return func(opts *ClientOptions) {
@@ -208,11 +331,16 @@ func WithParams(params map[string]string) ClientOption {
        }
 }
 
-func WithGeneric(generic string) ClientOption {
-       return func(opts *ClientOptions) {
-               opts.Reference.Generic = generic
-       }
-}
+// todo(DMwangnima): implement this functionality
+//func WithGeneric(generic bool) ClientOption {
+//     return func(opts *ClientOptions) {
+//             if generic {
+//                     opts.Reference.Generic = "true"
+//             } else {
+//                     opts.Reference.Generic = "false"
+//             }
+//     }
+//}
 
 func WithSticky(sticky bool) ClientOption {
        return func(opts *ClientOptions) {
@@ -220,9 +348,9 @@ func WithSticky(sticky bool) ClientOption {
        }
 }
 
-func WithRequestTimeout(timeout string) ClientOption {
+func WithRequestTimeout(timeout time.Duration) ClientOption {
        return func(opts *ClientOptions) {
-               opts.Reference.RequestTimeout = timeout
+               opts.Reference.RequestTimeout = timeout.String()
        }
 }
 
@@ -245,51 +373,35 @@ func WithMeshProviderPort(port int) ClientOption {
 }
 
 // ---------- For framework ----------
+// These functions should not be invoked by users
 
-func WithRegistryConfig(key string, opts ...global.RegistryOption) 
ClientOption {
-       regCfg := new(global.RegistryConfig)
-       for _, opt := range opts {
-               opt(regCfg)
-       }
-
+func SetRegistries(regs map[string]*global.RegistryConfig) ClientOption {
        return func(opts *ClientOptions) {
-               if opts.Registries == nil {
-                       opts.Registries = 
make(map[string]*global.RegistryConfig)
-               }
-               opts.Registries[key] = regCfg
+               opts.Registries = regs
        }
 }
 
-func WithApplicationConfig(opts ...global.ApplicationOption) ClientOption {
-       appCfg := new(global.ApplicationConfig)
-       for _, opt := range opts {
-               opt(appCfg)
-       }
-
+func SetApplication(application *global.ApplicationConfig) ClientOption {
        return func(opts *ClientOptions) {
-               opts.Application = appCfg
+               opts.Application = application
        }
 }
 
-func WithConsumerConfig(opts ...global.ConsumerOption) ClientOption {
-       conCfg := new(global.ConsumerConfig)
-       for _, opt := range opts {
-               opt(conCfg)
-       }
-
+func SetConsumer(consumer *global.ConsumerConfig) ClientOption {
        return func(opts *ClientOptions) {
-               opts.Consumer = conCfg
+               opts.Consumer = consumer
        }
 }
 
-func WithReferenceConfig(opts ...global.ReferenceOption) ClientOption {
-       refCfg := new(global.ReferenceConfig)
-       for _, opt := range opts {
-               opt(refCfg)
+func SetReference(reference *global.ReferenceConfig) ClientOption {
+       return func(opts *ClientOptions) {
+               opts.Reference = reference
        }
+}
 
+func SetShutdown(shutdown *global.ShutdownConfig) ClientOption {
        return func(opts *ClientOptions) {
-               opts.Reference = refCfg
+               opts.Shutdown = shutdown
        }
 }
 
diff --git a/common/constant/key.go b/common/constant/key.go
index 54c1ca3b4..2b6f1ca1d 100644
--- a/common/constant/key.go
+++ b/common/constant/key.go
@@ -144,6 +144,7 @@ const (
        CallHTTPTypeKey                    = "call-http-type"
        CallHTTP                           = "http"
        CallHTTP2                          = "http2"
+       ServiceInfoKey                     = "service-info"
 )
 
 const (
diff --git a/common/constant/serialization.go b/common/constant/serialization.go
index 620037da4..d1649f523 100644
--- a/common/constant/serialization.go
+++ b/common/constant/serialization.go
@@ -26,4 +26,5 @@ const (
        Hessian2Serialization = "hessian2"
        ProtobufSerialization = "protobuf"
        MsgpackSerialization  = "msgpack"
+       JSONSerialization     = "json"
 )
diff --git a/common/url.go b/common/url.go
index 3bc481bc9..79917a455 100644
--- a/common/url.go
+++ b/common/url.go
@@ -44,7 +44,6 @@ import (
 
 import (
        "dubbo.apache.org/dubbo-go/v3/common/constant"
-       "dubbo.apache.org/dubbo-go/v3/server"
 )
 
 // dubbo role type constant
@@ -111,11 +110,12 @@ type URL struct {
        paramsLock sync.RWMutex
        params     url.Values
 
-       Path       string // like  /com.ikurento.dubbo.UserProvider
-       Username   string
-       Password   string
-       Methods    []string
-       MethodInfo []server.MethodInfo
+       Path     string // like  /com.ikurento.dubbo.UserProvider
+       Username string
+       Password string
+       Methods  []string
+       // Attributes should not be transported
+       Attributes map[string]interface{} `hessian:"-"`
        // special for registry
        SubURL *URL
 }
@@ -220,10 +220,13 @@ func WithToken(token string) Option {
        }
 }
 
-// WithMethodInfos sets methodInfos for URL
-func WithMethodInfos(methodInfos []server.MethodInfo) Option {
+// WithAttribute sets attribute for URL
+func WithAttribute(key string, attribute interface{}) Option {
        return func(url *URL) {
-               url.MethodInfo = methodInfos
+               if url.Attributes == nil {
+                       url.Attributes = make(map[string]interface{})
+               }
+               url.Attributes[key] = attribute
        }
 }
 
@@ -778,7 +781,8 @@ func MergeURL(serviceURL *URL, referenceURL *URL) *URL {
        }
 
        // finally execute methodConfigMergeFcn
-       for _, method := range referenceURL.Methods {
+       mergedURL.Methods = make([]string, len(referenceURL.Methods))
+       for i, method := range referenceURL.Methods {
                for _, paramKey := range []string{constant.LoadbalanceKey, 
constant.ClusterKey, constant.RetriesKey, constant.TimeoutKey} {
                        if v := referenceURL.GetParam(paramKey, ""); len(v) > 0 
{
                                params[paramKey] = []string{v}
@@ -790,6 +794,7 @@ func MergeURL(serviceURL *URL, referenceURL *URL) *URL {
                                params[methodsKey] = []string{v}
                        }
                        //}
+                       mergedURL.Methods[i] = method
                }
        }
        // In this way, we will raise some performance.
diff --git a/compat.go b/compat.go
index 182ff1311..19202bfee 100644
--- a/compat.go
+++ b/compat.go
@@ -27,6 +27,9 @@ import (
 )
 
 func compatRootConfig(c *InstanceOptions) *config.RootConfig {
+       if c == nil {
+               return nil
+       }
        proCompat := make(map[string]*config.ProtocolConfig)
        for k, v := range c.Protocols {
                proCompat[k] = compatProtocolConfig(v)
@@ -63,6 +66,9 @@ func compatRootConfig(c *InstanceOptions) *config.RootConfig {
 }
 
 func compatApplicationConfig(c *global.ApplicationConfig) 
*config.ApplicationConfig {
+       if c == nil {
+               return nil
+       }
        return &config.ApplicationConfig{
                Organization: c.Organization,
                Name:         c.Name,
@@ -77,6 +83,9 @@ func compatApplicationConfig(c *global.ApplicationConfig) 
*config.ApplicationCon
 }
 
 func compatProtocolConfig(c *global.ProtocolConfig) *config.ProtocolConfig {
+       if c == nil {
+               return nil
+       }
        return &config.ProtocolConfig{
                Name:                 c.Name,
                Ip:                   c.Ip,
@@ -88,6 +97,9 @@ func compatProtocolConfig(c *global.ProtocolConfig) 
*config.ProtocolConfig {
 }
 
 func compatRegistryConfig(c *global.RegistryConfig) *config.RegistryConfig {
+       if c == nil {
+               return nil
+       }
        return &config.RegistryConfig{
                Protocol:          c.Protocol,
                Timeout:           c.Timeout,
@@ -109,6 +121,9 @@ func compatRegistryConfig(c *global.RegistryConfig) 
*config.RegistryConfig {
 }
 
 func compatCenterConfig(c *global.CenterConfig) *config.CenterConfig {
+       if c == nil {
+               return nil
+       }
        return &config.CenterConfig{
                Protocol:      c.Protocol,
                Address:       c.Address,
@@ -126,6 +141,9 @@ func compatCenterConfig(c *global.CenterConfig) 
*config.CenterConfig {
 }
 
 func compatMetadataReportConfig(c *global.MetadataReportConfig) 
*config.MetadataReportConfig {
+       if c == nil {
+               return nil
+       }
        return &config.MetadataReportConfig{
                Protocol:  c.Protocol,
                Address:   c.Address,
@@ -138,12 +156,20 @@ func compatMetadataReportConfig(c 
*global.MetadataReportConfig) *config.Metadata
 }
 
 func compatProviderConfig(c *global.ProviderConfig) *config.ProviderConfig {
+       if c == nil {
+               return nil
+       }
+       services := make(map[string]*config.ServiceConfig)
+       for key, svc := range c.Services {
+               services[key] = compatServiceConfig(svc)
+       }
        return &config.ProviderConfig{
                Filter:                 c.Filter,
                Register:               c.Register,
                RegistryIDs:            c.RegistryIDs,
                ProtocolIDs:            c.ProtocolIDs,
                TracingKey:             c.TracingKey,
+               Services:               services,
                ProxyFactory:           c.ProxyFactory,
                FilterConf:             c.FilterConf,
                ConfigType:             c.ConfigType,
@@ -152,7 +178,81 @@ func compatProviderConfig(c *global.ProviderConfig) 
*config.ProviderConfig {
        }
 }
 
+func compatServiceConfig(c *global.ServiceConfig) *config.ServiceConfig {
+       if c == nil {
+               return nil
+       }
+       methods := make([]*config.MethodConfig, len(c.Methods))
+       for i, method := range c.Methods {
+               methods[i] = compatMethodConfig(method)
+       }
+       protocols := make(map[string]*config.ProtocolConfig)
+       for key, pro := range c.RCProtocolsMap {
+               protocols[key] = compatProtocolConfig(pro)
+       }
+       registries := make(map[string]*config.RegistryConfig)
+       for key, reg := range c.RCRegistriesMap {
+               registries[key] = compatRegistryConfig(reg)
+       }
+       return &config.ServiceConfig{
+               Filter:                      c.Filter,
+               ProtocolIDs:                 c.ProtocolIDs,
+               Interface:                   c.Interface,
+               RegistryIDs:                 c.RegistryIDs,
+               Cluster:                     c.Cluster,
+               Loadbalance:                 c.Loadbalance,
+               Group:                       c.Group,
+               Version:                     c.Version,
+               Methods:                     methods,
+               Warmup:                      c.Warmup,
+               Retries:                     c.Retries,
+               Serialization:               c.Serialization,
+               Params:                      c.Params,
+               Token:                       c.Token,
+               AccessLog:                   c.AccessLog,
+               TpsLimiter:                  c.TpsLimiter,
+               TpsLimitInterval:            c.TpsLimitInterval,
+               TpsLimitRate:                c.TpsLimitRate,
+               TpsLimitStrategy:            c.TpsLimitStrategy,
+               TpsLimitRejectedHandler:     c.TpsLimitRejectedHandler,
+               ExecuteLimit:                c.ExecuteLimit,
+               ExecuteLimitRejectedHandler: c.ExecuteLimitRejectedHandler,
+               Auth:                        c.Auth,
+               NotRegister:                 c.NotRegister,
+               ParamSign:                   c.ParamSign,
+               Tag:                         c.Tag,
+               TracingKey:                  c.TracingKey,
+               RCProtocolsMap:              protocols,
+               RCRegistriesMap:             registries,
+               ProxyFactoryKey:             c.ProxyFactoryKey,
+       }
+}
+
+func compatMethodConfig(c *global.MethodConfig) *config.MethodConfig {
+       if c == nil {
+               return nil
+       }
+       return &config.MethodConfig{
+               InterfaceId:                 c.InterfaceId,
+               InterfaceName:               c.InterfaceName,
+               Name:                        c.Name,
+               Retries:                     c.Retries,
+               LoadBalance:                 c.LoadBalance,
+               Weight:                      c.Weight,
+               TpsLimitInterval:            c.TpsLimitInterval,
+               TpsLimitRate:                c.TpsLimitRate,
+               TpsLimitStrategy:            c.TpsLimitStrategy,
+               ExecuteLimit:                c.ExecuteLimit,
+               ExecuteLimitRejectedHandler: c.ExecuteLimitRejectedHandler,
+               Sticky:                      c.Sticky,
+               RequestTimeout:              c.RequestTimeout,
+       }
+}
+
 func compatConsumerConfig(c *global.ConsumerConfig) *config.ConsumerConfig {
+       if c == nil {
+               return nil
+       }
        return &config.ConsumerConfig{
                Filter:                         c.Filter,
                RegistryIDs:                    c.RegistryIDs,
@@ -169,6 +269,9 @@ func compatConsumerConfig(c *global.ConsumerConfig) 
*config.ConsumerConfig {
 }
 
 func compatMetricConfig(c *global.MetricConfig) *config.MetricConfig {
+       if c == nil {
+               return nil
+       }
        return &config.MetricConfig{
                Mode:               c.Mode,
                Namespace:          c.Namespace,
@@ -182,6 +285,9 @@ func compatMetricConfig(c *global.MetricConfig) 
*config.MetricConfig {
 }
 
 func compatTracingConfig(c *global.TracingConfig) *config.TracingConfig {
+       if c == nil {
+               return nil
+       }
        return &config.TracingConfig{
                Name:        c.Name,
                ServiceName: c.ServiceName,
@@ -191,6 +297,9 @@ func compatTracingConfig(c *global.TracingConfig) 
*config.TracingConfig {
 }
 
 func compatLoggerConfig(c *global.LoggerConfig) *config.LoggerConfig {
+       if c == nil {
+               return nil
+       }
        return &config.LoggerConfig{
                Driver:   c.Driver,
                Level:    c.Level,
@@ -201,6 +310,9 @@ func compatLoggerConfig(c *global.LoggerConfig) 
*config.LoggerConfig {
 }
 
 func compatFile(c *global.File) *config.File {
+       if c == nil {
+               return nil
+       }
        return &config.File{
                Name:       c.Name,
                MaxSize:    c.MaxSize,
@@ -211,6 +323,9 @@ func compatFile(c *global.File) *config.File {
 }
 
 func compatShutdownConfig(c *global.ShutdownConfig) *config.ShutdownConfig {
+       if c == nil {
+               return nil
+       }
        cfg := &config.ShutdownConfig{
                Timeout:                     c.Timeout,
                StepTimeout:                 c.StepTimeout,
@@ -226,18 +341,27 @@ func compatShutdownConfig(c *global.ShutdownConfig) 
*config.ShutdownConfig {
 }
 
 func compatCustomConfig(c *global.CustomConfig) *config.CustomConfig {
+       if c == nil {
+               return nil
+       }
        return &config.CustomConfig{
                ConfigMap: c.ConfigMap,
        }
 }
 
 func compatProfilesConfig(c *global.ProfilesConfig) *config.ProfilesConfig {
+       if c == nil {
+               return nil
+       }
        return &config.ProfilesConfig{
                Active: c.Active,
        }
 }
 
 func compatTLSConfig(c *global.TLSConfig) *config.TLSConfig {
+       if c == nil {
+               return nil
+       }
        return &config.TLSConfig{
                CACertFile:    c.CACertFile,
                TLSCertFile:   c.TLSCertFile,
diff --git a/dubbo.go b/dubbo.go
index 18629b45a..6513653d5 100644
--- a/dubbo.go
+++ b/dubbo.go
@@ -24,6 +24,7 @@ import (
 import (
        "dubbo.apache.org/dubbo-go/v3/client"
        "dubbo.apache.org/dubbo-go/v3/global"
+       "dubbo.apache.org/dubbo-go/v3/server"
 )
 
 // Instance is the highest layer conception that user could touch. It is 
mapped from RootConfig.
@@ -58,62 +59,30 @@ func (ins *Instance) NewClient(opts ...client.ClientOption) 
(*client.Client, err
        conCfg := ins.insOpts.Consumer
        appCfg := ins.insOpts.Application
        regsCfg := ins.insOpts.Registries
-       // todo(DMwangnima): use slices to maintain options
+       sdCfg := ins.insOpts.Shutdown
        if conCfg != nil {
+               refCfg := &global.ReferenceConfig{
+                       Check:       &conCfg.Check,
+                       Filter:      conCfg.Filter,
+                       Protocol:    conCfg.Protocol,
+                       RegistryIDs: conCfg.RegistryIDs,
+                       TracingKey:  conCfg.TracingKey,
+               }
                // these options come from Consumer and Root.
                // for dubbo-go developers, referring 
config/ConsumerConfig.Init and config/ReferenceConfig
                cliOpts = append(cliOpts,
-                       client.WithReferenceConfig(
-                               global.WithReference_Filter(conCfg.Filter),
-                               
global.WithReference_RegistryIDs(conCfg.RegistryIDs),
-                               global.WithReference_Protocol(conCfg.Protocol),
-                               
global.WithReference_TracingKey(conCfg.TracingKey),
-                               global.WithReference_Check(conCfg.Check),
-                       ),
-                       client.WithConsumerConfig(
-                               
global.WithConsumer_MeshEnabled(conCfg.MeshEnabled),
-                               
global.WithConsumer_AdaptiveService(conCfg.AdaptiveService),
-                               
global.WithConsumer_ProxyFactory(conCfg.ProxyFactory),
-                       ),
+                       client.SetReference(refCfg),
+                       client.SetConsumer(conCfg),
                )
        }
        if appCfg != nil {
-               cliOpts = append(cliOpts,
-                       client.WithApplicationConfig(
-                               global.WithApplication_Name(appCfg.Name),
-                               
global.WithApplication_Organization(appCfg.Organization),
-                               global.WithApplication_Module(appCfg.Module),
-                               global.WithApplication_Version(appCfg.Version),
-                               global.WithApplication_Owner(appCfg.Owner),
-                               
global.WithApplication_Environment(appCfg.Environment),
-                               global.WithApplication_Group(appCfg.Group),
-                               
global.WithApplication_MetadataType(appCfg.MetadataType),
-                       ),
-               )
+               cliOpts = append(cliOpts, client.SetApplication(appCfg))
        }
        if regsCfg != nil {
-               for key, reg := range regsCfg {
-                       cliOpts = append(cliOpts,
-                               client.WithRegistryConfig(key,
-                                       
global.WithRegistry_Protocol(reg.Protocol),
-                                       
global.WithRegistry_Timeout(reg.Timeout),
-                                       global.WithRegistry_Group(reg.Group),
-                                       
global.WithRegistry_Namespace(reg.Namespace),
-                                       global.WithRegistry_TTL(reg.TTL),
-                                       
global.WithRegistry_Address(reg.Address),
-                                       
global.WithRegistry_Username(reg.Username),
-                                       
global.WithRegistry_Password(reg.Password),
-                                       
global.WithRegistry_Simplified(reg.Simplified),
-                                       
global.WithRegistry_Preferred(reg.Preferred),
-                                       global.WithRegistry_Zone(reg.Zone),
-                                       global.WithRegistry_Weight(reg.Weight),
-                                       global.WithRegistry_Params(reg.Params),
-                                       
global.WithRegistry_RegistryType(reg.RegistryType),
-                                       
global.WithRegistry_UseAsMetaReport(reg.UseAsMetaReport),
-                                       
global.WithRegistry_UseAsConfigCenter(reg.UseAsConfigCenter),
-                               ),
-                       )
-               }
+               cliOpts = append(cliOpts, client.SetRegistries(regsCfg))
+       }
+       if sdCfg != nil {
+               cliOpts = append(cliOpts, client.SetShutdown(sdCfg))
        }
        // options passed by users has higher priority
        cliOpts = append(cliOpts, opts...)
@@ -125,3 +94,52 @@ func (ins *Instance) NewClient(opts ...client.ClientOption) 
(*client.Client, err
 
        return cli, nil
 }
+
+// NewServer is like server.NewServer, but inject configurations from 
RootConfig.
+func (ins *Instance) NewServer(opts ...server.ServerOption) (*server.Server, 
error) {
+       if ins == nil || ins.insOpts == nil {
+               return nil, errors.New("Instance has not been initialized")
+       }
+
+       var srvOpts []server.ServerOption
+       appCfg := ins.insOpts.Application
+       regsCfg := ins.insOpts.Registries
+       prosCfg := ins.insOpts.Protocols
+       trasCfg := ins.insOpts.Tracing
+       sdCfg := ins.insOpts.Shutdown
+       if appCfg != nil {
+               srvOpts = append(srvOpts,
+                       server.SetServer_Application(appCfg),
+                       //server.WithServer_ApplicationConfig(
+                       //      global.WithApplication_Name(appCfg.Name),
+                       //      
global.WithApplication_Organization(appCfg.Organization),
+                       //      global.WithApplication_Module(appCfg.Module),
+                       //      global.WithApplication_Version(appCfg.Version),
+                       //      global.WithApplication_Owner(appCfg.Owner),
+                       //      
global.WithApplication_Environment(appCfg.Environment),
+                       //),
+               )
+       }
+       if regsCfg != nil {
+               srvOpts = append(srvOpts, server.SetServer_Registries(regsCfg))
+       }
+       if prosCfg != nil {
+               srvOpts = append(srvOpts, server.SetServer_Protocols(prosCfg))
+       }
+       if trasCfg != nil {
+               srvOpts = append(srvOpts, server.SetServer_Tracings(trasCfg))
+       }
+       if sdCfg != nil {
+               srvOpts = append(srvOpts, server.SetServer_Shutdown(sdCfg))
+       }
+
+       // options passed by users have higher priority
+       srvOpts = append(srvOpts, opts...)
+
+       srv, err := server.NewServer(srvOpts...)
+       if err != nil {
+               return nil, err
+       }
+
+       return srv, nil
+}
diff --git a/global/profiles_config.go b/global/profiles_config.go
index eb7185409..d829dd836 100644
--- a/global/profiles_config.go
+++ b/global/profiles_config.go
@@ -23,7 +23,7 @@ type ProfilesConfig struct {
 }
 
 func DefaultProfilesConfig() *ProfilesConfig {
-       return nil
+       return &ProfilesConfig{}
 }
 
 type ProfilesOption func(*ProfilesConfig)
diff --git a/global/protocol_config.go b/global/protocol_config.go
index 2872c5b06..25f1ae2b7 100644
--- a/global/protocol_config.go
+++ b/global/protocol_config.go
@@ -31,6 +31,10 @@ type ProtocolConfig struct {
        MaxServerRecvMsgSize string `default:"4mib" 
yaml:"max-server-recv-msg-size" json:"max-server-recv-msg-size,omitempty"`
 }
 
+func DefaultProtocolConfig() *ProtocolConfig {
+       return &ProtocolConfig{}
+}
+
 type ProtocolOption func(*ProtocolConfig)
 
 func WithProtocol_Name(name string) ProtocolOption {
@@ -51,9 +55,9 @@ func WithProtocol_Port(port string) ProtocolOption {
        }
 }
 
-func WithProtocol_Param(param interface{}) ProtocolOption {
+func WithProtocol_Params(params interface{}) ProtocolOption {
        return func(cfg *ProtocolConfig) {
-               cfg.Params = param
+               cfg.Params = params
        }
 }
 
diff --git a/global/provider_config.go b/global/provider_config.go
index 3edc5e054..ffba16ec2 100644
--- a/global/provider_config.go
+++ b/global/provider_config.go
@@ -29,11 +29,11 @@ type ProviderConfig struct {
        // TracingKey is tracing ids list
        TracingKey string `yaml:"tracing-key" json:"tracing-key" 
property:"tracing-key"`
        // there is no need to configure Services
-       //// Services services
-       //Services     map[string]*server.ServiceConfig `yaml:"services" 
json:"services,omitempty" property:"services"`
-       ProxyFactory string            `default:"default" yaml:"proxy" 
json:"proxy,omitempty" property:"proxy"`
-       FilterConf   interface{}       `yaml:"filter_conf" 
json:"filter_conf,omitempty" property:"filter_conf"`
-       ConfigType   map[string]string `yaml:"config_type" 
json:"config_type,omitempty" property:"config_type"`
+       // Services services
+       Services     map[string]*ServiceConfig `yaml:"services" 
json:"services,omitempty" property:"services"`
+       ProxyFactory string                    `default:"default" yaml:"proxy" 
json:"proxy,omitempty" property:"proxy"`
+       FilterConf   interface{}               `yaml:"filter_conf" 
json:"filter_conf,omitempty" property:"filter_conf"`
+       ConfigType   map[string]string         `yaml:"config_type" 
json:"config_type,omitempty" property:"config_type"`
        // adaptive service
        AdaptiveService        bool `yaml:"adaptive-service" 
json:"adaptive-service" property:"adaptive-service"`
        AdaptiveServiceVerbose bool `yaml:"adaptive-service-verbose" 
json:"adaptive-service-verbose" property:"adaptive-service-verbose"`
@@ -43,6 +43,7 @@ func DefaultProviderConfig() *ProviderConfig {
        return &ProviderConfig{
                RegistryIDs: make([]string, 8),
                ProtocolIDs: make([]string, 8),
+               Services:    make(map[string]*ServiceConfig),
        }
 }
 
diff --git a/global/reference_config.go b/global/reference_config.go
index 092edd07c..94070fd09 100644
--- a/global/reference_config.go
+++ b/global/reference_config.go
@@ -47,15 +47,17 @@ type ReferenceConfig struct {
        MeshProviderPort int               `yaml:"mesh-provider-port" 
json:"mesh-provider-port,omitempty" propertiy:"mesh-provider-port"`
 }
 
-type ReferenceOption func(*ReferenceConfig)
-
 func DefaultReferenceConfig() *ReferenceConfig {
        return &ReferenceConfig{
-               Methods: make([]*MethodConfig, 0, 8),
-               Params:  make(map[string]string, 8),
+               // use Triple protocol by default
+               Protocol: "tri",
+               Methods:  make([]*MethodConfig, 0, 8),
+               Params:   make(map[string]string, 8),
        }
 }
 
+type ReferenceOption func(*ReferenceConfig)
+
 func WithReference_InterfaceName(name string) ReferenceOption {
        return func(cfg *ReferenceConfig) {
                cfg.InterfaceName = name
@@ -88,7 +90,7 @@ func WithReference_Protocol(protocol string) ReferenceOption {
 
 func WithReference_RegistryIDs(registryIDs []string) ReferenceOption {
        return func(cfg *ReferenceConfig) {
-               if len(registryIDs) <= 0 {
+               if len(registryIDs) >= 0 {
                        cfg.RegistryIDs = registryIDs
                }
        }
diff --git a/global/registry_config.go b/global/registry_config.go
index 7330ef2a9..f96ff5250 100644
--- a/global/registry_config.go
+++ b/global/registry_config.go
@@ -41,6 +41,10 @@ type RegistryConfig struct {
        UseAsConfigCenter bool              `default:"true" 
yaml:"use-as-config-center" json:"use-as-config-center,omitempty" 
property:"use-as-config-center"`
 }
 
+func DefaultRegistryConfig() *RegistryConfig {
+       return &RegistryConfig{}
+}
+
 type RegistryOption func(*RegistryConfig)
 
 func WithRegistry_Protocol(protocol string) RegistryOption {
diff --git a/global/service_config.go b/global/service_config.go
index a098e975b..95d271dc7 100644
--- a/global/service_config.go
+++ b/global/service_config.go
@@ -29,14 +29,20 @@ type ServiceConfig struct {
        ParamSign                   string            `yaml:"param.sign" 
json:"param.sign,omitempty" property:"param.sign"`
        Tag                         string            `yaml:"tag" 
json:"tag,omitempty" property:"tag"`
        TracingKey                  string            `yaml:"tracing-key" 
json:"tracing-key,omitempty" propertiy:"tracing-key"`
+
+       RCProtocolsMap  map[string]*ProtocolConfig
+       RCRegistriesMap map[string]*RegistryConfig
+       ProxyFactoryKey string
 }
 
 type ServiceOption func(*ServiceConfig)
 
 func DefaultServiceConfig() *ServiceConfig {
        return &ServiceConfig{
-               Methods: make([]*MethodConfig, 0, 8),
-               Params:  make(map[string]string, 8),
+               Methods:         make([]*MethodConfig, 0, 8),
+               Params:          make(map[string]string, 8),
+               RCProtocolsMap:  make(map[string]*ProtocolConfig),
+               RCRegistriesMap: make(map[string]*RegistryConfig),
        }
 }
 
@@ -205,3 +211,27 @@ func WithService_TracingKey(tracingKey string) 
ServiceOption {
                cfg.TracingKey = tracingKey
        }
 }
+
+func WithService_RCProtocol(name string, protocol *ProtocolConfig) 
ServiceOption {
+       return func(cfg *ServiceConfig) {
+               if cfg.RCProtocolsMap == nil {
+                       cfg.RCProtocolsMap = make(map[string]*ProtocolConfig)
+               }
+               cfg.RCProtocolsMap[name] = protocol
+       }
+}
+
+func WithService_RCRegistry(name string, registry *RegistryConfig) 
ServiceOption {
+       return func(cfg *ServiceConfig) {
+               if cfg.RCRegistriesMap == nil {
+                       cfg.RCRegistriesMap = make(map[string]*RegistryConfig)
+               }
+               cfg.RCRegistriesMap[name] = registry
+       }
+}
+
+func WithService_ProxyFactoryKey(factory string) ServiceOption {
+       return func(cfg *ServiceConfig) {
+               cfg.ProxyFactoryKey = factory
+       }
+}
diff --git a/global/tls_config.go b/global/tls_config.go
index 84f79bdd2..f6b1e56e7 100644
--- a/global/tls_config.go
+++ b/global/tls_config.go
@@ -26,6 +26,7 @@ type TLSConfig struct {
 }
 
 func DefaultTLSConfig() *TLSConfig {
+       // please refer to /config/tls_config.go NewTLSConfigBuilder
        return nil
 }
 
diff --git a/graceful_shutdown/common.go b/graceful_shutdown/common.go
index b12f7427f..82cc4ccf4 100644
--- a/graceful_shutdown/common.go
+++ b/graceful_shutdown/common.go
@@ -18,10 +18,25 @@
 package graceful_shutdown
 
 import (
-       "github.com/dubbogo/gost/log/logger"
        "time"
 )
 
+import (
+       hessian "github.com/apache/dubbo-go-hessian2"
+
+       "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+)
+
+func init() {
+       hessian.RegisterPOJO(&common.MetadataInfo{})
+       hessian.RegisterPOJO(&common.ServiceInfo{})
+       hessian.RegisterPOJO(&common.URL{})
+}
+
 func parseDuration(timeout string, desc string, def time.Duration) 
time.Duration {
        res, err := time.ParseDuration(timeout)
        if err != nil {
diff --git a/graceful_shutdown/compat.go b/graceful_shutdown/compat.go
index b462a57c3..f8b80bbd8 100644
--- a/graceful_shutdown/compat.go
+++ b/graceful_shutdown/compat.go
@@ -17,10 +17,13 @@
 
 package graceful_shutdown
 
+import (
+       "go.uber.org/atomic"
+)
+
 import (
        "dubbo.apache.org/dubbo-go/v3/config"
        "dubbo.apache.org/dubbo-go/v3/global"
-       "go.uber.org/atomic"
 )
 
 func compatShutdownConfig(c *global.ShutdownConfig) *config.ShutdownConfig {
diff --git a/graceful_shutdown/options.go b/graceful_shutdown/options.go
index d0a112293..e364bb9d9 100644
--- a/graceful_shutdown/options.go
+++ b/graceful_shutdown/options.go
@@ -17,26 +17,78 @@
 
 package graceful_shutdown
 
-import "dubbo.apache.org/dubbo-go/v3/global"
+import (
+       "time"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/global"
+)
 
 var (
        defOpts = &Options{
-               shutdown: global.DefaultShutdownConfig(),
+               Shutdown: global.DefaultShutdownConfig(),
        }
 )
 
 type Options struct {
-       shutdown *global.ShutdownConfig
+       Shutdown *global.ShutdownConfig
 }
 
-func defaultOptions() *Options {
+func DefaultOptions() *Options {
        return defOpts
 }
 
 type Option func(*Options)
 
+func WithTimeout(timeout time.Duration) Option {
+       return func(opts *Options) {
+               opts.Shutdown.Timeout = timeout.String()
+       }
+}
+
+func WithStepTimeout(timeout time.Duration) Option {
+       return func(opts *Options) {
+               opts.Shutdown.StepTimeout = timeout.String()
+       }
+}
+
+func WithConsumerUpdateWaitTime(duration time.Duration) Option {
+       return func(opts *Options) {
+               opts.Shutdown.ConsumerUpdateWaitTime = duration.String()
+       }
+}
+
+// todo(DMwangnima): add more specified configuration API
+//func WithRejectRequestHandler(handler string) Option {
+//     return func(opts *Options) {
+//             opts.Shutdown.RejectRequestHandler = handler
+//     }
+//}
+
+func WithoutInternalSignal() Option {
+       return func(opts *Options) {
+               signal := false
+               opts.Shutdown.InternalSignal = &signal
+       }
+}
+
+func WithOfflineRequestWindowTimeout(timeout time.Duration) Option {
+       return func(opts *Options) {
+               opts.Shutdown.OfflineRequestWindowTimeout = timeout.String()
+       }
+}
+
+func WithRejectRequest() Option {
+       return func(opts *Options) {
+               opts.Shutdown.RejectRequest.Store(true)
+       }
+}
+
+// ---------- For framework ----------
+
 func WithShutdown_Config(cfg *global.ShutdownConfig) Option {
        return func(opts *Options) {
-               opts.shutdown = cfg
+               opts.Shutdown = cfg
        }
 }
diff --git a/graceful_shutdown/shutdown.go b/graceful_shutdown/shutdown.go
index 73e70c3b8..b560ed6c9 100644
--- a/graceful_shutdown/shutdown.go
+++ b/graceful_shutdown/shutdown.go
@@ -18,10 +18,6 @@
 package graceful_shutdown
 
 import (
-       "dubbo.apache.org/dubbo-go/v3/common/constant"
-       "dubbo.apache.org/dubbo-go/v3/common/extension"
-       "dubbo.apache.org/dubbo-go/v3/config"
-       "github.com/dubbogo/gost/log/logger"
        "os"
        "os/signal"
        "runtime/debug"
@@ -29,6 +25,16 @@ import (
        "time"
 )
 
+import (
+       "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/common/extension"
+       "dubbo.apache.org/dubbo-go/v3/config"
+)
+
 const (
        // todo(DMwangnima): these descriptions and defaults could be wrapped 
by functions of Options
        defaultTimeout                     = 60 * time.Second
@@ -52,11 +58,12 @@ var (
 
 func Init(opts ...Option) {
        initOnce.Do(func() {
-               newOpts := defaultOptions()
+               protocols = make(map[string]struct{})
+               newOpts := DefaultOptions()
                for _, opt := range opts {
                        opt(newOpts)
                }
-               compatShutdown = compatShutdownConfig(newOpts.shutdown)
+               compatShutdown = compatShutdownConfig(newOpts.Shutdown)
                // retrieve ShutdownConfig for gracefulShutdownFilter
                cGracefulShutdownFilter, existcGracefulShutdownFilter := 
extension.GetFilter(constant.GracefulShutdownConsumerFilterKey)
                if !existcGracefulShutdownFilter {
diff --git a/loader.go b/loader.go
new file mode 100644
index 000000000..5679c25e1
--- /dev/null
+++ b/loader.go
@@ -0,0 +1,347 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dubbo
+
+import (
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "runtime"
+       "strings"
+)
+
+import (
+       "github.com/dubbogo/gost/log/logger"
+
+       "github.com/knadh/koanf"
+       "github.com/knadh/koanf/parsers/json"
+       "github.com/knadh/koanf/parsers/toml"
+       "github.com/knadh/koanf/parsers/yaml"
+       "github.com/knadh/koanf/providers/confmap"
+       "github.com/knadh/koanf/providers/rawbytes"
+
+       "github.com/pkg/errors"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/common/constant/file"
+       "dubbo.apache.org/dubbo-go/v3/config/parsers/properties"
+)
+
+var (
+       defaultActive   = "default"
+       instanceOptions = defaultInstanceOptions()
+)
+
+func Load(opts ...LoaderConfOption) error {
+       // conf
+       conf := NewLoaderConf(opts...)
+       if conf.opts == nil {
+               koan := GetConfigResolver(conf)
+               koan = conf.MergeConfig(koan)
+               if err := koan.UnmarshalWithConf(instanceOptions.Prefix(),
+                       instanceOptions, koanf.UnmarshalConf{Tag: "yaml"}); err 
!= nil {
+                       return err
+               }
+       } else {
+               instanceOptions = conf.opts
+       }
+
+       if err := instanceOptions.init(); err != nil {
+               return err
+       }
+
+       // todo(DMwangnima): use independent Consumer and Provider logic
+       return nil
+}
+
+type loaderConf struct {
+       suffix string           // loaderConf file extension default yaml
+       path   string           // loaderConf file path default 
./conf/dubbogo.yaml
+       delim  string           // loaderConf file delim default .
+       bytes  []byte           // config bytes
+       opts   *InstanceOptions // user provide InstanceOptions built by 
WithXXX api
+       name   string           // config file name
+}
+
+func NewLoaderConf(opts ...LoaderConfOption) *loaderConf {
+       configFilePath := "../conf/dubbogo.yaml"
+       if configFilePathFromEnv := os.Getenv(constant.ConfigFileEnvKey); 
configFilePathFromEnv != "" {
+               configFilePath = configFilePathFromEnv
+       }
+       name, suffix := resolverFilePath(configFilePath)
+       conf := &loaderConf{
+               suffix: suffix,
+               path:   absolutePath(configFilePath),
+               delim:  ".",
+               name:   name,
+       }
+       for _, opt := range opts {
+               opt.apply(conf)
+       }
+       if conf.opts != nil {
+               return conf
+       }
+       if len(conf.bytes) <= 0 {
+               if bytes, err := ioutil.ReadFile(conf.path); err != nil {
+                       panic(err)
+               } else {
+                       conf.bytes = bytes
+               }
+       }
+       return conf
+}
+
+type LoaderConfOption interface {
+       apply(vc *loaderConf)
+}
+
+type loaderConfigFunc func(*loaderConf)
+
+func (fn loaderConfigFunc) apply(vc *loaderConf) {
+       fn(vc)
+}
+
+// WithGenre set load config file suffix
+// Deprecated: replaced by WithSuffix
+func WithGenre(suffix string) LoaderConfOption {
+       return loaderConfigFunc(func(conf *loaderConf) {
+               g := strings.ToLower(suffix)
+               if err := checkFileSuffix(g); err != nil {
+                       panic(err)
+               }
+               conf.suffix = g
+       })
+}
+
+// WithSuffix set load config file suffix
+func WithSuffix(suffix file.Suffix) LoaderConfOption {
+       return loaderConfigFunc(func(conf *loaderConf) {
+               conf.suffix = string(suffix)
+       })
+}
+
+// WithPath set load config path
+func WithPath(path string) LoaderConfOption {
+       return loaderConfigFunc(func(conf *loaderConf) {
+               conf.path = absolutePath(path)
+               if bytes, err := ioutil.ReadFile(conf.path); err != nil {
+                       panic(err)
+               } else {
+                       conf.bytes = bytes
+               }
+               name, suffix := resolverFilePath(path)
+               conf.suffix = suffix
+               conf.name = name
+       })
+}
+
+func WithInstanceOptions(opts *InstanceOptions) LoaderConfOption {
+       return loaderConfigFunc(func(conf *loaderConf) {
+               conf.opts = opts
+       })
+}
+
+func WithDelim(delim string) LoaderConfOption {
+       return loaderConfigFunc(func(conf *loaderConf) {
+               conf.delim = delim
+       })
+}
+
+// WithBytes set load config  bytes
+func WithBytes(bytes []byte) LoaderConfOption {
+       return loaderConfigFunc(func(conf *loaderConf) {
+               conf.bytes = bytes
+       })
+}
+
+// absolutePath get absolut path
+func absolutePath(inPath string) string {
+
+       if inPath == "$HOME" || strings.HasPrefix(inPath, 
"$HOME"+string(os.PathSeparator)) {
+               inPath = userHomeDir() + inPath[5:]
+       }
+
+       if filepath.IsAbs(inPath) {
+               return filepath.Clean(inPath)
+       }
+
+       p, err := filepath.Abs(inPath)
+       if err == nil {
+               return filepath.Clean(p)
+       }
+
+       return ""
+}
+
+// userHomeDir get gopath
+func userHomeDir() string {
+       if runtime.GOOS == "windows" {
+               home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
+               if home == "" {
+                       home = os.Getenv("USERPROFILE")
+               }
+               return home
+       }
+       return os.Getenv("HOME")
+}
+
+// checkFileSuffix check file suffix
+func checkFileSuffix(suffix string) error {
+       for _, g := range []string{"json", "toml", "yaml", "yml", "properties"} 
{
+               if g == suffix {
+                       return nil
+               }
+       }
+       return errors.Errorf("no support file suffix: %s", suffix)
+}
+
+// resolverFilePath resolver file path
+// eg: give a ./conf/dubbogo.yaml return dubbogo and yaml
+func resolverFilePath(path string) (name, suffix string) {
+       paths := strings.Split(path, "/")
+       fileName := strings.Split(paths[len(paths)-1], ".")
+       if len(fileName) < 2 {
+               return fileName[0], string(file.YAML)
+       }
+       return fileName[0], fileName[1]
+}
+
+// MergeConfig merge config file
+func (conf *loaderConf) MergeConfig(koan *koanf.Koanf) *koanf.Koanf {
+       var (
+               activeKoan *koanf.Koanf
+               activeConf *loaderConf
+       )
+       active := koan.String("dubbo.profiles.active")
+       active = getLegalActive(active)
+       logger.Infof("The following profiles are active: %s", active)
+       if defaultActive != active {
+               path := conf.getActiveFilePath(active)
+               if !pathExists(path) {
+                       logger.Debugf("Config file:%s not exist skip config 
merge", path)
+                       return koan
+               }
+               activeConf = NewLoaderConf(WithPath(path))
+               activeKoan = GetConfigResolver(activeConf)
+               if err := koan.Merge(activeKoan); err != nil {
+                       logger.Debugf("Config merge err %s", err)
+               }
+       }
+       return koan
+}
+
+func (conf *loaderConf) getActiveFilePath(active string) string {
+       suffix := constant.DotSeparator + conf.suffix
+       return strings.ReplaceAll(conf.path, suffix, "") + "-" + active + suffix
+}
+
+func pathExists(path string) bool {
+       if _, err := os.Stat(path); err == nil {
+               return true
+       } else {
+               return !os.IsNotExist(err)
+       }
+}
+
+// getLegalActive if active is null return default
+func getLegalActive(active string) string {
+       if len(active) == 0 {
+               return defaultActive
+       }
+       return active
+}
+
+// GetConfigResolver get config resolver
+func GetConfigResolver(conf *loaderConf) *koanf.Koanf {
+       var (
+               k   *koanf.Koanf
+               err error
+       )
+       if len(conf.suffix) <= 0 {
+               conf.suffix = string(file.YAML)
+       }
+       if len(conf.delim) <= 0 {
+               conf.delim = "."
+       }
+       bytes := conf.bytes
+       if len(bytes) <= 0 {
+               panic(errors.New("bytes is nil,please set bytes or file path"))
+       }
+       k = koanf.New(conf.delim)
+
+       switch conf.suffix {
+       case "yaml", "yml":
+               err = k.Load(rawbytes.Provider(bytes), yaml.Parser())
+       case "json":
+               err = k.Load(rawbytes.Provider(bytes), json.Parser())
+       case "toml":
+               err = k.Load(rawbytes.Provider(bytes), toml.Parser())
+       case "properties":
+               err = k.Load(rawbytes.Provider(bytes), properties.Parser())
+       default:
+               err = errors.Errorf("no support %s file suffix", conf.suffix)
+       }
+
+       if err != nil {
+               panic(err)
+       }
+       return resolvePlaceholder(k)
+}
+
+// resolvePlaceholder replace ${xx} with real value
+func resolvePlaceholder(resolver *koanf.Koanf) *koanf.Koanf {
+       m := make(map[string]interface{})
+       for k, v := range resolver.All() {
+               s, ok := v.(string)
+               if !ok {
+                       continue
+               }
+               newKey, defaultValue := checkPlaceholder(s)
+               if newKey == "" {
+                       continue
+               }
+               m[k] = resolver.Get(newKey)
+               if m[k] == nil {
+                       m[k] = defaultValue
+               }
+       }
+       err := resolver.Load(confmap.Provider(m, resolver.Delim()), nil)
+       if err != nil {
+               logger.Errorf("resolvePlaceholder error %s", err)
+       }
+       return resolver
+}
+
+func checkPlaceholder(s string) (newKey, defaultValue string) {
+       s = strings.TrimSpace(s)
+       if !strings.HasPrefix(s, file.PlaceholderPrefix) || 
!strings.HasSuffix(s, file.PlaceholderSuffix) {
+               return
+       }
+       s = s[len(file.PlaceholderPrefix) : len(s)-len(file.PlaceholderSuffix)]
+       indexColon := strings.Index(s, ":")
+       if indexColon == -1 {
+               newKey = strings.TrimSpace(s)
+               return
+       }
+       newKey = strings.TrimSpace(s[0:indexColon])
+       defaultValue = strings.TrimSpace(s[indexColon+1:])
+
+       return
+}
diff --git a/metadata/metadata.go b/metadata/metadata.go
new file mode 100644
index 000000000..b35ac2979
--- /dev/null
+++ b/metadata/metadata.go
@@ -0,0 +1,86 @@
+/*
+ * 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 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"
+)
+
+var (
+       exporting = &atomic.Bool{}
+)
+
+func ExportMetadataService() {
+       ms, err := extension.GetLocalMetadataService(constant.DefaultKey)
+       if err != nil {
+               logger.Warnf("could not init metadata service", err)
+               return
+       }
+
+       if exporting.Load() {
+               return
+       }
+
+       // In theory, we can use sync.Once
+       // But sync.Once is not reentrant.
+       // Now the invocation chain is createRegistry -> tryInitMetadataService 
-> metadataServiceExporter.export
+       // -> createRegistry -> initMetadataService...
+       // So using sync.Once will result in dead lock
+       exporting.Store(true)
+
+       expt := extension.GetMetadataServiceExporter(constant.DefaultKey, ms)
+       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)
+       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/local/service.go 
b/metadata/service/local/service.go
index aeac070fa..440953e07 100644
--- a/metadata/service/local/service.go
+++ b/metadata/service/local/service.go
@@ -67,6 +67,7 @@ var (
 func GetLocalMetadataService() (service.MetadataService, error) {
        metadataServiceInitOnce.Do(func() {
                metadataServiceInstance = &MetadataService{
+                       // todo(DMwangnima): use external config
                        BaseMetadataService:   
service.NewBaseMetadataService(config.GetApplicationConfig().Name),
                        exportedServiceURLs:   &sync.Map{},
                        subscribedServiceURLs: &sync.Map{},
diff --git a/options.go b/options.go
index 65a667f79..51e9b2df0 100644
--- a/options.go
+++ b/options.go
@@ -18,7 +18,16 @@
 package dubbo
 
 import (
+       "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/config"
        "dubbo.apache.org/dubbo-go/v3/global"
+       "dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
+       "dubbo.apache.org/dubbo-go/v3/protocol"
+       "dubbo.apache.org/dubbo-go/v3/registry"
 )
 
 type InstanceOptions struct {
@@ -66,176 +75,301 @@ func (rc *InstanceOptions) init(opts ...InstanceOption) 
error {
                opt(rc)
        }
 
+       // remaining procedure is like RootConfig.Init() without 
RootConfig.Start()
+       // tasks of RootConfig.Start() would be decomposed to Client and Server
        rcCompat := compatRootConfig(rc)
-       if err := rcCompat.Init(); err != nil {
+       if err := rcCompat.Logger.Init(); err != nil { // init default logger
                return err
        }
-
-       return nil
-}
-
-type InstanceOption func(*InstanceOptions)
-
-func WithApplication(opts ...global.ApplicationOption) InstanceOption {
-       appCfg := new(global.ApplicationConfig)
-       for _, opt := range opts {
-               opt(appCfg)
+       if err := rcCompat.ConfigCenter.Init(rcCompat); err != nil {
+               logger.Infof("[Config Center] Config center doesn't start")
+               logger.Debugf("config center doesn't start because %s", err)
+       } else {
+               if err = rcCompat.Logger.Init(); err != nil { // init logger 
using config from config center again
+                       return err
+               }
        }
 
-       return func(cfg *InstanceOptions) {
-               cfg.Application = appCfg
+       if err := rcCompat.Application.Init(); err != nil {
+               return err
        }
-}
 
-func WithProtocol(key string, opts ...global.ProtocolOption) InstanceOption {
-       proCfg := new(global.ProtocolConfig)
-       for _, opt := range opts {
-               opt(proCfg)
+       // init user define
+       if err := rcCompat.Custom.Init(); err != nil {
+               return err
        }
 
-       return func(cfg *InstanceOptions) {
-               if cfg.Protocols == nil {
-                       cfg.Protocols = make(map[string]*global.ProtocolConfig)
+       // init protocol
+       protocols := rcCompat.Protocols
+       if len(protocols) <= 0 {
+               protocol := &config.ProtocolConfig{}
+               protocols = make(map[string]*config.ProtocolConfig, 1)
+               protocols[constant.Dubbo] = protocol
+               rcCompat.Protocols = protocols
+       }
+       for _, protocol := range protocols {
+               if err := protocol.Init(); err != nil {
+                       return err
                }
-               cfg.Protocols[key] = proCfg
        }
-}
 
-func WithRegistry(key string, opts ...global.RegistryOption) InstanceOption {
-       regCfg := new(global.RegistryConfig)
-       for _, opt := range opts {
-               opt(regCfg)
+       // init registry
+       registries := rcCompat.Registries
+       if registries != nil {
+               for _, reg := range registries {
+                       if err := reg.Init(); err != nil {
+                               return err
+                       }
+               }
        }
 
-       return func(cfg *InstanceOptions) {
-               if cfg.Registries == nil {
-                       cfg.Registries = make(map[string]*global.RegistryConfig)
+       if err := rcCompat.MetadataReport.Init(rcCompat); err != nil {
+               return err
+       }
+       if err := rcCompat.Metric.Init(); err != nil {
+               return err
+       }
+       for _, t := range rcCompat.Tracing {
+               if err := t.Init(); err != nil {
+                       return err
                }
-               cfg.Registries[key] = regCfg
        }
-}
 
-func WithConfigCenter(opts ...global.CenterOption) InstanceOption {
-       ccCfg := new(global.CenterConfig)
-       for _, opt := range opts {
-               opt(ccCfg)
+       routers := rcCompat.Router
+       if len(routers) > 0 {
+               for _, r := range routers {
+                       if err := r.Init(); err != nil {
+                               return err
+                       }
+               }
+               rcCompat.Router = routers
        }
 
-       return func(cfg *InstanceOptions) {
-               cfg.ConfigCenter = ccCfg
+       // provider、consumer must last init
+       if err := rcCompat.Provider.Init(rcCompat); err != nil {
+               return err
        }
-}
-
-func WithMetadataReport(opts ...global.MetadataReportOption) InstanceOption {
-       mrCfg := new(global.MetadataReportConfig)
-       for _, opt := range opts {
-               opt(mrCfg)
+       if err := rcCompat.Consumer.Init(rcCompat); err != nil {
+               return err
        }
-
-       return func(cfg *InstanceOptions) {
-               cfg.MetadataReport = mrCfg
+       if err := rcCompat.Shutdown.Init(); err != nil {
+               return err
        }
-}
+       config.SetRootConfig(*rcCompat)
 
-func WithConsumer(opts ...global.ConsumerOption) InstanceOption {
-       conCfg := new(global.ConsumerConfig)
-       for _, opt := range opts {
-               opt(conCfg)
-       }
+       return nil
+}
 
-       return func(cfg *InstanceOptions) {
-               cfg.Consumer = conCfg
-       }
+func (rc *InstanceOptions) Prefix() string {
+       return constant.Dubbo
 }
 
-func WithMetric(opts ...global.MetricOption) InstanceOption {
-       meCfg := new(global.MetricConfig)
-       for _, opt := range opts {
-               opt(meCfg)
-       }
+type InstanceOption func(*InstanceOptions)
 
-       return func(cfg *InstanceOptions) {
-               cfg.Metric = meCfg
+func WithOrganization(organization string) InstanceOption {
+       return func(opts *InstanceOptions) {
+               opts.Application.Organization = organization
        }
 }
 
-func WithTracing(key string, opts ...global.TracingOption) InstanceOption {
-       traCfg := new(global.TracingConfig)
-       for _, opt := range opts {
-               opt(traCfg)
+func WithName(name string) InstanceOption {
+       return func(opts *InstanceOptions) {
+               opts.Application.Name = name
        }
+}
 
-       return func(cfg *InstanceOptions) {
-               if cfg.Tracing == nil {
-                       cfg.Tracing = make(map[string]*global.TracingConfig)
-               }
-               cfg.Tracing[key] = traCfg
+func WithModule(module string) InstanceOption {
+       return func(opts *InstanceOptions) {
+               opts.Application.Module = module
        }
 }
 
-func WithLogger(opts ...global.LoggerOption) InstanceOption {
-       logCfg := new(global.LoggerConfig)
-       for _, opt := range opts {
-               opt(logCfg)
+func WithGroup(group string) InstanceOption {
+       return func(opts *InstanceOptions) {
+               opts.Application.Group = group
        }
+}
 
-       return func(cfg *InstanceOptions) {
-               cfg.Logger = logCfg
+func WithVersion(version string) InstanceOption {
+       return func(opts *InstanceOptions) {
+               opts.Application.Version = version
        }
 }
 
-func WithShutdown(opts ...global.ShutdownOption) InstanceOption {
-       sdCfg := new(global.ShutdownConfig)
-       for _, opt := range opts {
-               opt(sdCfg)
+func WithOwner(owner string) InstanceOption {
+       return func(opts *InstanceOptions) {
+               opts.Application.Owner = owner
        }
+}
 
-       return func(cfg *InstanceOptions) {
-               cfg.Shutdown = sdCfg
+func WithEnvironment(environment string) InstanceOption {
+       return func(opts *InstanceOptions) {
+               opts.Application.Environment = environment
        }
 }
 
-func WithEventDispatcherType(typ string) InstanceOption {
-       return func(cfg *InstanceOptions) {
-               cfg.EventDispatcherType = typ
+func WithRemoteMetadata() InstanceOption {
+       return func(opts *InstanceOptions) {
+               opts.Application.MetadataType = 
constant.RemoteMetadataStorageType
        }
 }
 
-func WithCacheFile(file string) InstanceOption {
-       return func(cfg *InstanceOptions) {
-               cfg.CacheFile = file
+func WithTag(tag string) InstanceOption {
+       return func(opts *InstanceOptions) {
+               opts.Application.Tag = tag
        }
 }
 
-func WithCustom(opts ...global.CustomOption) InstanceOption {
-       cusCfg := new(global.CustomConfig)
+func WithProtocol(key string, opts ...protocol.Option) InstanceOption {
+       proOpts := protocol.DefaultOptions()
        for _, opt := range opts {
-               opt(cusCfg)
+               opt(proOpts)
        }
 
-       return func(cfg *InstanceOptions) {
-               cfg.Custom = cusCfg
+       return func(insOpts *InstanceOptions) {
+               if insOpts.Protocols == nil {
+                       insOpts.Protocols = 
make(map[string]*global.ProtocolConfig)
+               }
+               insOpts.Protocols[key] = proOpts.Protocol
        }
 }
 
-func WithProfiles(opts ...global.ProfilesOption) InstanceOption {
-       proCfg := new(global.ProfilesConfig)
+func WithRegistry(key string, opts ...registry.Option) InstanceOption {
+       regOpts := registry.DefaultOptions()
        for _, opt := range opts {
-               opt(proCfg)
+               opt(regOpts)
        }
 
-       return func(cfg *InstanceOptions) {
-               cfg.Profiles = proCfg
+       return func(insOpts *InstanceOptions) {
+               if insOpts.Registries == nil {
+                       insOpts.Registries = 
make(map[string]*global.RegistryConfig)
+               }
+               insOpts.Registries[key] = regOpts.Registry
        }
 }
 
-func WithTLS(opts ...global.TLSOption) InstanceOption {
-       tlsCfg := new(global.TLSConfig)
+//func WithConfigCenter(opts ...global.CenterOption) InstanceOption {
+//     ccCfg := new(global.CenterConfig)
+//     for _, opt := range opts {
+//             opt(ccCfg)
+//     }
+//
+//     return func(cfg *InstanceOptions) {
+//             cfg.ConfigCenter = ccCfg
+//     }
+//}
+
+//func WithMetadataReport(opts ...global.MetadataReportOption) InstanceOption {
+//     mrCfg := new(global.MetadataReportConfig)
+//     for _, opt := range opts {
+//             opt(mrCfg)
+//     }
+//
+//     return func(cfg *InstanceOptions) {
+//             cfg.MetadataReport = mrCfg
+//     }
+//}
+
+//func WithConsumer(opts ...global.ConsumerOption) InstanceOption {
+//     conCfg := new(global.ConsumerConfig)
+//     for _, opt := range opts {
+//             opt(conCfg)
+//     }
+//
+//     return func(cfg *InstanceOptions) {
+//             cfg.Consumer = conCfg
+//     }
+//}
+
+//func WithMetric(opts ...global.MetricOption) InstanceOption {
+//     meCfg := new(global.MetricConfig)
+//     for _, opt := range opts {
+//             opt(meCfg)
+//     }
+//
+//     return func(cfg *InstanceOptions) {
+//             cfg.Metric = meCfg
+//     }
+//}
+
+//func WithTracing(key string, opts ...global.TracingOption) InstanceOption {
+//     traCfg := new(global.TracingConfig)
+//     for _, opt := range opts {
+//             opt(traCfg)
+//     }
+//
+//     return func(cfg *InstanceOptions) {
+//             if cfg.Tracing == nil {
+//                     cfg.Tracing = make(map[string]*global.TracingConfig)
+//             }
+//             cfg.Tracing[key] = traCfg
+//     }
+//}
+
+//func WithLogger(opts ...global.LoggerOption) InstanceOption {
+//     logCfg := new(global.LoggerConfig)
+//     for _, opt := range opts {
+//             opt(logCfg)
+//     }
+//
+//     return func(cfg *InstanceOptions) {
+//             cfg.Logger = logCfg
+//     }
+//}
+
+func WithShutdown(opts ...graceful_shutdown.Option) InstanceOption {
+       sdOpts := graceful_shutdown.DefaultOptions()
        for _, opt := range opts {
-               opt(tlsCfg)
+               opt(sdOpts)
        }
 
-       return func(cfg *InstanceOptions) {
-               cfg.TLSConfig = tlsCfg
+       return func(insOpts *InstanceOptions) {
+               insOpts.Shutdown = sdOpts.Shutdown
        }
 }
+
+// todo(DMwangnima): enumerate specific EventDispatcherType
+//func WithEventDispatcherType(typ string) InstanceOption {
+//     return func(cfg *InstanceOptions) {
+//             cfg.EventDispatcherType = typ
+//     }
+//}
+
+//func WithCacheFile(file string) InstanceOption {
+//     return func(cfg *InstanceOptions) {
+//             cfg.CacheFile = file
+//     }
+//}
+
+//func WithCustom(opts ...global.CustomOption) InstanceOption {
+//     cusCfg := new(global.CustomConfig)
+//     for _, opt := range opts {
+//             opt(cusCfg)
+//     }
+//
+//     return func(cfg *InstanceOptions) {
+//             cfg.Custom = cusCfg
+//     }
+//}
+
+//func WithProfiles(opts ...global.ProfilesOption) InstanceOption {
+//     proCfg := new(global.ProfilesConfig)
+//     for _, opt := range opts {
+//             opt(proCfg)
+//     }
+//
+//     return func(cfg *InstanceOptions) {
+//             cfg.Profiles = proCfg
+//     }
+//}
+
+//func WithTLS(opts ...global.TLSOption) InstanceOption {
+//     tlsCfg := new(global.TLSConfig)
+//     for _, opt := range opts {
+//             opt(tlsCfg)
+//     }
+//
+//     return func(cfg *InstanceOptions) {
+//             cfg.TLSConfig = tlsCfg
+//     }
+//}
diff --git a/protocol/dubbo3/dubbo3_protocol.go 
b/protocol/dubbo3/dubbo3_protocol.go
index 8d824b95d..c3b6e7f4a 100644
--- a/protocol/dubbo3/dubbo3_protocol.go
+++ b/protocol/dubbo3/dubbo3_protocol.go
@@ -40,7 +40,6 @@ import (
 import (
        "dubbo.apache.org/dubbo-go/v3/common"
        "dubbo.apache.org/dubbo-go/v3/common/constant"
-       "dubbo.apache.org/dubbo-go/v3/common/extension"
        "dubbo.apache.org/dubbo-go/v3/config"
        "dubbo.apache.org/dubbo-go/v3/protocol"
        "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
@@ -49,7 +48,8 @@ import (
 var protocolOnce sync.Once
 
 func init() {
-       extension.SetProtocol(tripleConstant.TRIPLE, GetProtocol)
+       // todo(DMwangnima): deprecated
+       //extension.SetProtocol(tripleConstant.TRIPLE, GetProtocol)
        protocolOnce = sync.Once{}
 }
 
diff --git a/protocol/options.go b/protocol/options.go
new file mode 100644
index 000000000..6373e5964
--- /dev/null
+++ b/protocol/options.go
@@ -0,0 +1,96 @@
+/*
+ * 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 protocol
+
+import (
+       "strconv"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/global"
+)
+
+type Options struct {
+       Protocol *global.ProtocolConfig
+}
+
+func DefaultOptions() *Options {
+       return &Options{Protocol: global.DefaultProtocolConfig()}
+}
+
+type Option func(*Options)
+
+func WithDubbo() Option {
+       return func(opts *Options) {
+               opts.Protocol.Name = "dubbo"
+       }
+}
+
+func WithGRPC() Option {
+       return func(opts *Options) {
+               opts.Protocol.Name = "grpc"
+       }
+}
+
+func WithJSONRPC() Option {
+       return func(opts *Options) {
+               opts.Protocol.Name = "jsonrpc"
+       }
+}
+
+func WithREST() Option {
+       return func(opts *Options) {
+               opts.Protocol.Name = "rest"
+       }
+}
+
+func WithTriple() Option {
+       return func(opts *Options) {
+               opts.Protocol.Name = "tri"
+       }
+}
+
+func WithIp(ip string) Option {
+       return func(opts *Options) {
+               opts.Protocol.Ip = ip
+       }
+}
+
+func WithPort(port int) Option {
+       return func(opts *Options) {
+               opts.Protocol.Port = strconv.Itoa(port)
+       }
+}
+
+func WithParams(params interface{}) Option {
+       return func(opts *Options) {
+               opts.Protocol.Params = params
+       }
+}
+
+func WithMaxServerSendMsgSize(size int) Option {
+       return func(opts *Options) {
+               opts.Protocol.MaxServerSendMsgSize = strconv.Itoa(size)
+       }
+}
+
+func WithMaxServerRecvMsgSize(size int) Option {
+       return func(opts *Options) {
+               opts.Protocol.MaxServerRecvMsgSize = strconv.Itoa(size)
+       }
+}
diff --git a/protocol/triple/client.go b/protocol/triple/client.go
index ff11db4e2..9d1f3fa4f 100644
--- a/protocol/triple/client.go
+++ b/protocol/triple/client.go
@@ -28,8 +28,6 @@ import (
 )
 
 import (
-       "github.com/dubbogo/gost/log/logger"
-
        "github.com/dustin/go-humanize"
 
        "golang.org/x/net/http2"
@@ -38,7 +36,6 @@ import (
 import (
        "dubbo.apache.org/dubbo-go/v3/common"
        "dubbo.apache.org/dubbo-go/v3/common/constant"
-       "dubbo.apache.org/dubbo-go/v3/config"
        tri "dubbo.apache.org/dubbo-go/v3/protocol/triple/triple_protocol"
 )
 
@@ -137,6 +134,16 @@ func newClientManager(url *common.URL) (*clientManager, 
error) {
        }
        triClientOpts = append(triClientOpts, 
tri.WithSendMaxBytes(maxCallSendMsgSize))
 
+       // set serialization
+       serialization := url.GetParam(constant.SerializationKey, 
constant.ProtobufSerialization)
+       switch serialization {
+       case constant.ProtobufSerialization:
+       case constant.JSONSerialization:
+               triClientOpts = append(triClientOpts, tri.WithProtoJSON())
+       default:
+               panic(fmt.Sprintf("Unsupported serialization: %s", 
serialization))
+       }
+
        // todo:// process timeout
        // consumer config client connectTimeout
        //connectTimeout := config.GetConsumerConfig().ConnectTimeout
@@ -157,22 +164,22 @@ func newClientManager(url *common.URL) (*clientManager, 
error) {
        // )
        var cfg *tls.Config
        var tlsFlag bool
-       var err error
-
-       // todo: move TLSConfig from root to consumer
-       if tlsConfig := config.GetRootConfig().TLSConfig; tlsConfig != nil {
-               cfg, err = config.GetClientTlsConfig(&config.TLSConfig{
-                       CACertFile:    tlsConfig.CACertFile,
-                       TLSCertFile:   tlsConfig.TLSCertFile,
-                       TLSKeyFile:    tlsConfig.TLSKeyFile,
-                       TLSServerName: tlsConfig.TLSServerName,
-               })
-               if err != nil {
-                       return nil, err
-               }
-               logger.Infof("TRIPLE clientManager initialized the TLSConfig 
configuration successfully")
-               tlsFlag = true
-       }
+       //var err error
+
+       // todo: think about a more elegant way to configure tls
+       //if tlsConfig := config.GetRootConfig().TLSConfig; tlsConfig != nil {
+       //      cfg, err = config.GetClientTlsConfig(&config.TLSConfig{
+       //              CACertFile:    tlsConfig.CACertFile,
+       //              TLSCertFile:   tlsConfig.TLSCertFile,
+       //              TLSKeyFile:    tlsConfig.TLSKeyFile,
+       //              TLSServerName: tlsConfig.TLSServerName,
+       //      })
+       //      if err != nil {
+       //              return nil, err
+       //      }
+       //      logger.Infof("TRIPLE clientManager initialized the TLSConfig 
configuration successfully")
+       //      tlsFlag = true
+       //}
 
        // todo(DMwangnima): this code fragment would be used to be compatible 
with old triple client
        //key := url.GetParam(constant.InterfaceKey, "")
@@ -205,7 +212,7 @@ func newClientManager(url *common.URL) (*clientManager, 
error) {
                }
                triClientOpts = append(triClientOpts)
        default:
-               panic(fmt.Sprintf("Unsupported type: %s", callType))
+               panic(fmt.Sprintf("Unsupported callType: %s", callType))
        }
        httpClient := &http.Client{
                Transport: transport,
diff --git a/protocol/triple/internal/client/cmd_classic/dubbogo.yml 
b/protocol/triple/internal/client/cmd_classic/dubbogo.yml
deleted file mode 100644
index acf53b3a5..000000000
--- a/protocol/triple/internal/client/cmd_classic/dubbogo.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-dubbo:
-  registries:
-    demoZK:
-      protocol: zookeeper
-      timeout: 3s
-      address: 127.0.0.1:2181
-  consumer:
-    references:
-      greet.GreetService:
-        protocol: grpc_new
-        interface: greet.GreetService
\ No newline at end of file
diff --git a/protocol/triple/internal/client/cmd_classic/main.go 
b/protocol/triple/internal/client/cmd_classic/main.go
deleted file mode 100644
index fcda07146..000000000
--- a/protocol/triple/internal/client/cmd_classic/main.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package main
-
-import (
-       "context"
-       "fmt"
-)
-
-import (
-       "dubbo.apache.org/dubbo-go/v3/config"
-       _ "dubbo.apache.org/dubbo-go/v3/imports"
-       greet "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto"
-       
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/triple_gen/greettriple"
-)
-
-func main() {
-       svc := new(greettriple.GreetServiceImpl)
-       greettriple.SetConsumerService(svc)
-       if err := config.Load(); err != nil {
-               panic(err)
-       }
-
-       resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: 
"dubbo"})
-       if err != nil {
-               panic(err)
-       }
-
-       fmt.Println(resp.Greeting)
-}
diff --git a/protocol/triple/internal/client/cmd_client/main.go 
b/protocol/triple/internal/client/cmd_client/main.go
index a630542de..7adb0fa7c 100644
--- a/protocol/triple/internal/client/cmd_client/main.go
+++ b/protocol/triple/internal/client/cmd_client/main.go
@@ -1,20 +1,33 @@
-package main
+/*
+ * 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.
+ */
 
-import (
-       "context"
-       "fmt"
-)
+package main
 
 import (
        "dubbo.apache.org/dubbo-go/v3/client"
-       greet "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto"
+       _ "dubbo.apache.org/dubbo-go/v3/imports"
+       "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/client/common"
        
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/triple_gen/greettriple"
 )
 
 func main() {
        // for the most brief RPC case
        cli, err := client.NewClient(
-               client.WithURL("127.0.0.1:20000"),
+               client.WithURL("tri://127.0.0.1:20000"),
        )
        if err != nil {
                panic(err)
@@ -24,10 +37,5 @@ func main() {
                panic(err)
        }
 
-       resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: 
"dubbo"})
-       if err != nil {
-               panic(err)
-       }
-
-       fmt.Println(resp.Greeting)
+       common.TestClient(svc)
 }
diff --git a/protocol/triple/internal/server/cmd/main.go 
b/protocol/triple/internal/client/cmd_client_with_registry/main.go
similarity index 70%
copy from protocol/triple/internal/server/cmd/main.go
copy to protocol/triple/internal/client/cmd_client_with_registry/main.go
index 4081a1845..4d2acb9d1 100644
--- a/protocol/triple/internal/server/cmd/main.go
+++ b/protocol/triple/internal/client/cmd_client_with_registry/main.go
@@ -18,19 +18,29 @@
 package main
 
 import (
+       "dubbo.apache.org/dubbo-go/v3/client"
        _ "dubbo.apache.org/dubbo-go/v3/imports"
+       "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/client/common"
        
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/triple_gen/greettriple"
-       "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/server/api"
-       "dubbo.apache.org/dubbo-go/v3/server"
+       "dubbo.apache.org/dubbo-go/v3/registry"
 )
 
 func main() {
-       srv, err := server.NewServer()
+       // for the most brief RPC case with Registry
+
+       cli, err := client.NewClient(
+               client.WithRegistry("zk",
+                       registry.WithZookeeper(),
+                       registry.WithAddress("127.0.0.1:2181"),
+               ),
+       )
        if err != nil {
                panic(err)
        }
-       if err := greettriple.RegisterGreetServiceHandler(srv, 
&api.GreetTripleServer{}); err != nil {
+       svc, err := greettriple.NewGreetService(cli)
+       if err != nil {
                panic(err)
        }
-       select {}
+
+       common.TestClient(svc)
 }
diff --git a/protocol/triple/internal/client/cmd_instance/main.go 
b/protocol/triple/internal/client/cmd_instance/main.go
index e1c17aa0d..262ca49af 100644
--- a/protocol/triple/internal/client/cmd_instance/main.go
+++ b/protocol/triple/internal/client/cmd_instance/main.go
@@ -1,15 +1,27 @@
-package main
+/*
+ * 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.
+ */
 
-import (
-       "context"
-       "fmt"
-)
+package main
 
 import (
-       dubbo "dubbo.apache.org/dubbo-go/v3"
+       "dubbo.apache.org/dubbo-go/v3"
        "dubbo.apache.org/dubbo-go/v3/client"
-       "dubbo.apache.org/dubbo-go/v3/global"
-       greet "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto"
+       _ "dubbo.apache.org/dubbo-go/v3/imports"
+       "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/client/common"
        
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/triple_gen/greettriple"
 )
 
@@ -17,22 +29,14 @@ func main() {
        // global conception
        // configure global configurations and common modules
        ins, err := dubbo.NewInstance(
-               dubbo.WithApplication(
-                       global.WithApplication_Name("dubbo_test"),
-               ),
-               dubbo.WithRegistry("nacos",
-                       global.WithRegistry_Address("127.0.0.1:8848"),
-               ),
-               dubbo.WithMetric(
-                       global.WithMetric_Enable(true),
-               ),
+               dubbo.WithName("dubbo_test"),
        )
        if err != nil {
                panic(err)
        }
        // configure the params that only client layer cares
        cli, err := ins.NewClient(
-               client.WithRetries(3),
+               client.WithURL("tri://127.0.0.1:20000"),
        )
        if err != nil {
                panic(err)
@@ -43,10 +47,5 @@ func main() {
                panic(err)
        }
 
-       resp, err := svc.Greet(context.Background(), &greet.GreetRequest{Name: 
"dubbo"})
-       if err != nil {
-               panic(err)
-       }
-
-       fmt.Println(resp.Greeting)
+       common.TestClient(svc)
 }
diff --git a/protocol/triple/internal/server/cmd/main.go 
b/protocol/triple/internal/client/cmd_instance_with_registry/main.go
similarity index 60%
copy from protocol/triple/internal/server/cmd/main.go
copy to protocol/triple/internal/client/cmd_instance_with_registry/main.go
index 4081a1845..38f9d3a1a 100644
--- a/protocol/triple/internal/server/cmd/main.go
+++ b/protocol/triple/internal/client/cmd_instance_with_registry/main.go
@@ -18,19 +18,39 @@
 package main
 
 import (
+       "dubbo.apache.org/dubbo-go/v3"
+       "dubbo.apache.org/dubbo-go/v3/client"
        _ "dubbo.apache.org/dubbo-go/v3/imports"
+       "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/client/common"
        
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/triple_gen/greettriple"
-       "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/server/api"
-       "dubbo.apache.org/dubbo-go/v3/server"
+       "dubbo.apache.org/dubbo-go/v3/registry"
 )
 
 func main() {
-       srv, err := server.NewServer()
+       // global conception
+       // configure global configurations and common modules
+       ins, err := dubbo.NewInstance(
+               dubbo.WithName("dubbo_test"),
+               dubbo.WithRegistry("zk",
+                       registry.WithZookeeper(),
+                       registry.WithAddress("127.0.0.1:2181"),
+               ),
+       )
        if err != nil {
                panic(err)
        }
-       if err := greettriple.RegisterGreetServiceHandler(srv, 
&api.GreetTripleServer{}); err != nil {
+       // configure the params that only client layer cares
+       cli, err := ins.NewClient(
+               client.WithRegistryIDs([]string{"zk"}),
+       )
+       if err != nil {
+               panic(err)
+       }
+
+       svc, err := greettriple.NewGreetService(cli)
+       if err != nil {
                panic(err)
        }
-       select {}
+
+       common.TestClient(svc)
 }
diff --git a/protocol/triple/internal/client/common/client.go 
b/protocol/triple/internal/client/common/client.go
new file mode 100644
index 000000000..af7f2570c
--- /dev/null
+++ b/protocol/triple/internal/client/common/client.go
@@ -0,0 +1,119 @@
+/*
+ * 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 common
+
+import (
+       "context"
+)
+
+import (
+       "github.com/dubbogo/gost/log/logger"
+)
+
+import (
+       greet "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto"
+       
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/triple_gen/greettriple"
+)
+
+func TestClient(cli greettriple.GreetService) {
+       if err := testUnary(cli); err != nil {
+               logger.Error(err)
+       }
+
+       if err := testBidiStream(cli); err != nil {
+               logger.Error(err)
+       }
+
+       if err := testClientStream(cli); err != nil {
+               logger.Error(err)
+       }
+
+       if err := testServerStream(cli); err != nil {
+               logger.Error(err)
+       }
+}
+
+func testUnary(cli greettriple.GreetService) error {
+       logger.Info("start to test TRIPLE unary call")
+       resp, err := cli.Greet(context.Background(), &greet.GreetRequest{Name: 
"triple"})
+       if err != nil {
+               return err
+       }
+       logger.Infof("TRIPLE unary call resp: %s", resp.Greeting)
+       return nil
+}
+
+func testBidiStream(cli greettriple.GreetService) error {
+       logger.Info("start to test TRIPLE bidi stream")
+       stream, err := cli.GreetStream(context.Background())
+       if err != nil {
+               return err
+       }
+       if err := stream.Send(&greet.GreetStreamRequest{Name: "triple"}); err 
!= nil {
+               return err
+       }
+       resp, err := stream.Recv()
+       if err != nil {
+               return err
+       }
+       logger.Infof("TRIPLE bidi stream resp: %s", resp.Greeting)
+       if err := stream.CloseRequest(); err != nil {
+               return err
+       }
+       if err := stream.CloseResponse(); err != nil {
+               return err
+       }
+       return nil
+}
+
+func testClientStream(cli greettriple.GreetService) error {
+       logger.Info("start to test TRIPLE client stream")
+       stream, err := cli.GreetClientStream(context.Background())
+       if err != nil {
+               return err
+       }
+       for i := 0; i < 5; i++ {
+               if err := stream.Send(&greet.GreetClientStreamRequest{Name: 
"triple"}); err != nil {
+                       return err
+               }
+       }
+       resp, err := stream.CloseAndRecv()
+       if err != nil {
+               return err
+       }
+       logger.Infof("TRIPLE client stream resp: %s", resp.Greeting)
+       return nil
+}
+
+func testServerStream(cli greettriple.GreetService) error {
+       logger.Info("start to test TRIPLE server stream")
+       stream, err := cli.GreetServerStream(context.Background(), 
&greet.GreetServerStreamRequest{Name: "triple"})
+       if err != nil {
+               return err
+       }
+       for stream.Recv() {
+               logger.Infof("TRIPLE server stream resp: %s", 
stream.Msg().Greeting)
+       }
+       if stream.Err() != nil {
+               return err
+       }
+       if err := stream.Close(); err != nil {
+               return err
+       }
+       return nil
+}
diff --git a/protocol/triple/internal/dubbo3_server/cmd/dubbogo.yml 
b/protocol/triple/internal/dubbo3_server/cmd/dubbogo.yml
new file mode 100644
index 000000000..a3a562ff0
--- /dev/null
+++ b/protocol/triple/internal/dubbo3_server/cmd/dubbogo.yml
@@ -0,0 +1,13 @@
+dubbo:
+#  registries:
+#    zk:
+#      address: zookeeper://127.0.0.1:2181
+  protocols:
+    triple:
+      name: tri
+      port: 20001
+  provider:
+    services:
+      GreetDubbo3Server:
+        # interface is for registry
+        interface: greet.GreetService
\ No newline at end of file
diff --git a/protocol/triple/internal/dubbo3_server/cmd/main.go 
b/protocol/triple/internal/dubbo3_server/cmd/main.go
new file mode 100644
index 000000000..aac22da47
--- /dev/null
+++ b/protocol/triple/internal/dubbo3_server/cmd/main.go
@@ -0,0 +1,15 @@
+package main
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/config"
+       _ "dubbo.apache.org/dubbo-go/v3/imports"
+       
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/dubbo3_server/api"
+)
+
+func main() {
+       config.SetProviderService(&api.GreetDubbo3Server{})
+       if err := config.Load(config.WithPath("./dubbogo.yml")); err != nil {
+               panic(err)
+       }
+       select {}
+}
diff --git 
a/protocol/triple/internal/proto/triple_gen/greettriple/greet.triple.go 
b/protocol/triple/internal/proto/triple_gen/greettriple/greet.triple.go
index 066f6c9a2..69f104635 100644
--- a/protocol/triple/internal/proto/triple_gen/greettriple/greet.triple.go
+++ b/protocol/triple/internal/proto/triple_gen/greettriple/greet.triple.go
@@ -87,10 +87,8 @@ type GreetServiceImpl struct {
 }
 
 func (c *GreetServiceImpl) Greet(ctx context.Context, req *proto.GreetRequest, 
opts ...client.CallOption) (*proto.GreetResponse, error) {
-       triReq := triple_protocol.NewRequest(req)
        resp := new(proto.GreetResponse)
-       triResp := triple_protocol.NewResponse(resp)
-       if err := c.cli.CallUnary(ctx, triReq, triResp, "greet.GreetService", 
"Greet", opts...); err != nil {
+       if err := c.cli.CallUnary(ctx, req, resp, "greet.GreetService", 
"Greet", opts...); err != nil {
                return nil, err
        }
        return resp, nil
@@ -115,8 +113,7 @@ func (c *GreetServiceImpl) GreetClientStream(ctx 
context.Context, opts ...client
 }
 
 func (c *GreetServiceImpl) GreetServerStream(ctx context.Context, req 
*proto.GreetServerStreamRequest, opts ...client.CallOption) 
(GreetService_GreetServerStreamClient, error) {
-       triReq := triple_protocol.NewRequest(req)
-       stream, err := c.cli.CallServerStream(ctx, triReq, 
"greet.GreetService", "GreetServerStream", opts...)
+       stream, err := c.cli.CallServerStream(ctx, req, "greet.GreetService", 
"GreetServerStream", opts...)
        if err != nil {
                return nil, err
        }
@@ -230,8 +227,8 @@ type GreetServiceHandler interface {
        GreetServerStream(context.Context, *proto.GreetServerStreamRequest, 
GreetService_GreetServerStreamServer) error
 }
 
-func RegisterGreetServiceHandler(srv *server.Server, hdlr GreetServiceHandler) 
error {
-       return srv.Register(hdlr, &GreetService_ServiceInfo)
+func RegisterGreetServiceHandler(srv *server.Server, hdlr GreetServiceHandler, 
opts ...server.ServiceOption) error {
+       return srv.Register(hdlr, &GreetService_ServiceInfo, opts...)
 }
 
 type GreetService_GreetStreamServer interface {
diff --git a/protocol/triple/internal/server/cmd/dubbogo.yml 
b/protocol/triple/internal/server/cmd/dubbogo.yml
deleted file mode 100644
index 75d198680..000000000
--- a/protocol/triple/internal/server/cmd/dubbogo.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-dubbo:
-  registries:
-    demoZK:
-      protocol: zookeeper
-      address: 127.0.0.1:2181
-  protocols:
-    grpc_new:
-      name: grpc_new
-      port: 20000
-  provider:
-    services:
-      greet.GreetService:
-        interface: greet.GreetService
-        proxy: default
-        protocol-ids:
-          - grpc_new
\ No newline at end of file
diff --git a/protocol/triple/internal/server/cmd/main.go 
b/protocol/triple/internal/server/cmd_instance/main.go
similarity index 75%
copy from protocol/triple/internal/server/cmd/main.go
copy to protocol/triple/internal/server/cmd_instance/main.go
index 4081a1845..4c0006a12 100644
--- a/protocol/triple/internal/server/cmd/main.go
+++ b/protocol/triple/internal/server/cmd_instance/main.go
@@ -18,19 +18,31 @@
 package main
 
 import (
+       "dubbo.apache.org/dubbo-go/v3"
        _ "dubbo.apache.org/dubbo-go/v3/imports"
+       "dubbo.apache.org/dubbo-go/v3/protocol"
        
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/triple_gen/greettriple"
        "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/server/api"
-       "dubbo.apache.org/dubbo-go/v3/server"
 )
 
 func main() {
-       srv, err := server.NewServer()
+       // global conception
+       // configure global configurations and common modules
+       ins, err := dubbo.NewInstance(
+               dubbo.WithName("dubbo_test"),
+               dubbo.WithProtocol("tri",
+                       protocol.WithTriple(),
+                       protocol.WithPort(20000),
+               ),
+       )
+       srv, err := ins.NewServer()
        if err != nil {
                panic(err)
        }
        if err := greettriple.RegisterGreetServiceHandler(srv, 
&api.GreetTripleServer{}); err != nil {
                panic(err)
        }
-       select {}
+       if err := srv.Serve(); err != nil {
+               panic(err)
+       }
 }
diff --git a/protocol/triple/internal/server/cmd/main.go 
b/protocol/triple/internal/server/cmd_instance_with_registry/main.go
similarity index 69%
copy from protocol/triple/internal/server/cmd/main.go
copy to protocol/triple/internal/server/cmd_instance_with_registry/main.go
index 4081a1845..070421c55 100644
--- a/protocol/triple/internal/server/cmd/main.go
+++ b/protocol/triple/internal/server/cmd_instance_with_registry/main.go
@@ -18,19 +18,36 @@
 package main
 
 import (
+       "dubbo.apache.org/dubbo-go/v3"
        _ "dubbo.apache.org/dubbo-go/v3/imports"
+       "dubbo.apache.org/dubbo-go/v3/protocol"
        
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/triple_gen/greettriple"
        "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/server/api"
-       "dubbo.apache.org/dubbo-go/v3/server"
+       "dubbo.apache.org/dubbo-go/v3/registry"
 )
 
 func main() {
-       srv, err := server.NewServer()
+       // global conception
+       // configure global configurations and common modules
+       ins, err := dubbo.NewInstance(
+               dubbo.WithName("dubbo_test"),
+               dubbo.WithRegistry("zk",
+                       registry.WithZookeeper(),
+                       registry.WithAddress("127.0.0.1:2181"),
+               ),
+               dubbo.WithProtocol("tri",
+                       protocol.WithTriple(),
+                       protocol.WithPort(20000),
+               ),
+       )
+       srv, err := ins.NewServer()
        if err != nil {
                panic(err)
        }
        if err := greettriple.RegisterGreetServiceHandler(srv, 
&api.GreetTripleServer{}); err != nil {
                panic(err)
        }
-       select {}
+       if err := srv.Serve(); err != nil {
+               panic(err)
+       }
 }
diff --git a/protocol/triple/internal/server/cmd/main.go 
b/protocol/triple/internal/server/cmd_server/main.go
similarity index 84%
copy from protocol/triple/internal/server/cmd/main.go
copy to protocol/triple/internal/server/cmd_server/main.go
index 4081a1845..d7c5e5b20 100644
--- a/protocol/triple/internal/server/cmd/main.go
+++ b/protocol/triple/internal/server/cmd_server/main.go
@@ -19,18 +19,26 @@ package main
 
 import (
        _ "dubbo.apache.org/dubbo-go/v3/imports"
+       "dubbo.apache.org/dubbo-go/v3/protocol"
        
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/triple_gen/greettriple"
        "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/server/api"
        "dubbo.apache.org/dubbo-go/v3/server"
 )
 
 func main() {
-       srv, err := server.NewServer()
+       srv, err := server.NewServer(
+               server.WithServer_Protocol("tri",
+                       protocol.WithTriple(),
+                       protocol.WithPort(20000),
+               ),
+       )
        if err != nil {
                panic(err)
        }
        if err := greettriple.RegisterGreetServiceHandler(srv, 
&api.GreetTripleServer{}); err != nil {
                panic(err)
        }
-       select {}
+       if err := srv.Serve(); err != nil {
+               panic(err)
+       }
 }
diff --git a/protocol/triple/internal/server/cmd/main.go 
b/protocol/triple/internal/server/cmd_server_with_registry/main.go
similarity index 76%
rename from protocol/triple/internal/server/cmd/main.go
rename to protocol/triple/internal/server/cmd_server_with_registry/main.go
index 4081a1845..de2cc46aa 100644
--- a/protocol/triple/internal/server/cmd/main.go
+++ b/protocol/triple/internal/server/cmd_server_with_registry/main.go
@@ -19,18 +19,31 @@ package main
 
 import (
        _ "dubbo.apache.org/dubbo-go/v3/imports"
+       "dubbo.apache.org/dubbo-go/v3/protocol"
        
"dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/proto/triple_gen/greettriple"
        "dubbo.apache.org/dubbo-go/v3/protocol/triple/internal/server/api"
+       "dubbo.apache.org/dubbo-go/v3/registry"
        "dubbo.apache.org/dubbo-go/v3/server"
 )
 
 func main() {
-       srv, err := server.NewServer()
+       srv, err := server.NewServer(
+               server.WithServer_Registry("zk",
+                       registry.WithZookeeper(),
+                       registry.WithAddress("127.0.0.1:2181"),
+               ),
+               server.WithServer_Protocol("tri",
+                       protocol.WithTriple(),
+                       protocol.WithPort(20000),
+               ),
+       )
        if err != nil {
                panic(err)
        }
        if err := greettriple.RegisterGreetServiceHandler(srv, 
&api.GreetTripleServer{}); err != nil {
                panic(err)
        }
-       select {}
+       if err := srv.Serve(); err != nil {
+               panic(err)
+       }
 }
diff --git a/protocol/triple/server.go b/protocol/triple/server.go
index e8219cfba..64ece5796 100644
--- a/protocol/triple/server.go
+++ b/protocol/triple/server.go
@@ -82,6 +82,14 @@ func (s *Server) Start(invoker protocol.Invoker, info 
*server.ServiceInfo) {
        }
        hanOpts = append(hanOpts, tri.WithSendMaxBytes(maxServerSendMsgSize))
 
+       serialization := URL.GetParam(constant.SerializationKey, 
constant.ProtobufSerialization)
+       switch serialization {
+       case constant.ProtobufSerialization:
+       case constant.JSONSerialization:
+       default:
+               panic(fmt.Sprintf("Unsupported serialization: %s", 
serialization))
+       }
+
        // todo: implement interceptor
        // If global trace instance was set, then server tracer instance
        // can be get. If not, will return NoopTracer.
@@ -93,20 +101,21 @@ func (s *Server) Start(invoker protocol.Invoker, info 
*server.ServiceInfo) {
        //      grpc.MaxSendMsgSize(maxServerSendMsgSize),
        //)
        var cfg *tls.Config
-       tlsConfig := config.GetRootConfig().TLSConfig
-       if tlsConfig != nil {
-               cfg, err = config.GetServerTlsConfig(&config.TLSConfig{
-                       CACertFile:    tlsConfig.CACertFile,
-                       TLSCertFile:   tlsConfig.TLSCertFile,
-                       TLSKeyFile:    tlsConfig.TLSKeyFile,
-                       TLSServerName: tlsConfig.TLSServerName,
-               })
-               if err != nil {
-                       return
-               }
-               logger.Infof("Triple Server initialized the TLSConfig 
configuration")
-       }
-       srv.TLSConfig = cfg
+       // todo(DMwangnima): think about a more elegant way to configure tls
+       //tlsConfig := config.GetRootConfig().TLSConfig
+       //if tlsConfig != nil {
+       //      cfg, err = config.GetServerTlsConfig(&config.TLSConfig{
+       //              CACertFile:    tlsConfig.CACertFile,
+       //              TLSCertFile:   tlsConfig.TLSCertFile,
+       //              TLSKeyFile:    tlsConfig.TLSKeyFile,
+       //              TLSServerName: tlsConfig.TLSServerName,
+       //      })
+       //      if err != nil {
+       //              return
+       //      }
+       //      logger.Infof("Triple Server initialized the TLSConfig 
configuration")
+       //}
+       //srv.TLSConfig = cfg
 
        // todo:// open tracing
        hanOpts = append(hanOpts, tri.WithInterceptors())
@@ -186,7 +195,9 @@ func compatHandleService(mux *http.ServeMux, opts 
...tri.HandlerOption) {
                serviceKey := common.ServiceKey(providerService.Interface, 
providerService.Group, providerService.Version)
                exporter, _ := tripleProtocol.ExporterMap().Load(serviceKey)
                if exporter == nil {
-                       panic(fmt.Sprintf("no exporter found for servicekey: 
%v", serviceKey))
+                       // todo(DMwangnima): handler reflection Service and 
health Service
+                       continue
+                       //panic(fmt.Sprintf("no exporter found for servicekey: 
%v", serviceKey))
                }
                invoker := exporter.(protocol.Exporter).GetInvoker()
                if invoker == nil {
diff --git a/protocol/triple/triple-tool/gen/generator/genTriple.go 
b/protocol/triple/triple-tool/gen/generator/genTriple.go
index 0a0644ebd..246549b07 100644
--- a/protocol/triple/triple-tool/gen/generator/genTriple.go
+++ b/protocol/triple/triple-tool/gen/generator/genTriple.go
@@ -25,6 +25,7 @@ import (
 
 import (
        "github.com/emicklei/proto"
+
        "github.com/golang/protobuf/protoc-gen-go/descriptor"
 )
 
diff --git a/protocol/triple/triple.go b/protocol/triple/triple.go
index 4ec0742bf..cb64aa426 100644
--- a/protocol/triple/triple.go
+++ b/protocol/triple/triple.go
@@ -27,6 +27,7 @@ import (
 
 import (
        "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
        "dubbo.apache.org/dubbo-go/v3/common/extension"
        "dubbo.apache.org/dubbo-go/v3/protocol"
        "dubbo.apache.org/dubbo-go/v3/server"
@@ -34,7 +35,7 @@ import (
 
 const (
        // TRIPLE protocol name
-       TRIPLE = "triple"
+       TRIPLE = "tri"
 )
 
 var (
@@ -56,9 +57,10 @@ func (tp *TripleProtocol) Export(invoker protocol.Invoker) 
protocol.Exporter {
        url := invoker.GetURL()
        serviceKey := url.ServiceKey()
        // todo: retrieve this info from url
-       info := &server.ServiceInfo{
-               InterfaceName: url.Path,
-               Methods:       url.MethodInfo,
+       var info *server.ServiceInfo
+       infoRaw, ok := url.Attributes[constant.ServiceInfoKey]
+       if ok {
+               info = infoRaw.(*server.ServiceInfo)
        }
        exporter := NewTripleExporter(serviceKey, invoker, tp.ExporterMap())
        tp.SetExporterMap(serviceKey, exporter)
diff --git a/registry/exposed_tmp/exposed.go b/registry/exposed_tmp/exposed.go
new file mode 100644
index 000000000..f6861e068
--- /dev/null
+++ b/registry/exposed_tmp/exposed.go
@@ -0,0 +1,132 @@
+/*
+ * 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 exposed_tmp
+
+import (
+       "reflect"
+       "strconv"
+)
+
+import (
+       "github.com/dubbogo/gost/log/logger"
+
+       perrors "github.com/pkg/errors"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/common/extension"
+       "dubbo.apache.org/dubbo-go/v3/registry"
+)
+
+// RegisterServiceInstance register service instance
+func RegisterServiceInstance(applicationName string, tag string, metadataType 
string) {
+       url := selectMetadataServiceExportedURL()
+       if url == nil {
+               return
+       }
+       instance, err := createInstance(url, applicationName, tag, metadataType)
+       if err != nil {
+               panic(err)
+       }
+       p := extension.GetProtocol(constant.RegistryProtocol)
+       var rp registry.RegistryFactory
+       var ok bool
+       if rp, ok = p.(registry.RegistryFactory); !ok {
+               panic("dubbo registry protocol{" + reflect.TypeOf(p).String() + 
"} is invalid")
+       }
+       rs := rp.GetRegistries()
+       for _, r := range rs {
+               var sdr registry.ServiceDiscoveryHolder
+               if sdr, ok = r.(registry.ServiceDiscoveryHolder); !ok {
+                       continue
+               }
+               // publish app level data to registry
+               logger.Infof("Starting register instance address %v", instance)
+               err := sdr.GetServiceDiscovery().Register(instance)
+               if err != nil {
+                       panic(err)
+               }
+       }
+       // publish metadata to remote
+       if metadataType == constant.RemoteMetadataStorageType {
+               if remoteMetadataService, err := 
extension.GetRemoteMetadataService(); err == nil && remoteMetadataService != 
nil {
+                       remoteMetadataService.PublishMetadata(applicationName)
+               }
+       }
+}
+
+// // nolint
+func createInstance(url *common.URL, applicationName string, tag string, 
metadataType string) (registry.ServiceInstance, error) {
+       port, err := strconv.ParseInt(url.Port, 10, 32)
+       if err != nil {
+               return nil, perrors.WithMessage(err, "invalid port: "+url.Port)
+       }
+
+       host := url.Ip
+       if len(host) == 0 {
+               host = common.GetLocalIp()
+       }
+
+       // usually we will add more metadata
+       metadata := make(map[string]string, 8)
+       metadata[constant.MetadataStorageTypePropertyName] = metadataType
+
+       instance := &registry.DefaultServiceInstance{
+               ServiceName: applicationName,
+               Host:        host,
+               Port:        int(port),
+               ID:          host + constant.KeySeparator + url.Port,
+               Enable:      true,
+               Healthy:     true,
+               Metadata:    metadata,
+               Tag:         tag,
+       }
+
+       for _, cus := range extension.GetCustomizers() {
+               cus.Customize(instance)
+       }
+
+       return instance, nil
+}
+
+// selectMetadataServiceExportedURL get already be exported url
+func selectMetadataServiceExportedURL() *common.URL {
+       var selectedUrl *common.URL
+       metaDataService, err := 
extension.GetLocalMetadataService(constant.DefaultKey)
+       if err != nil {
+               logger.Warnf("get metadata service exporter failed, pls check 
if you import _ \"dubbo.apache.org/dubbo-go/v3/metadata/service/local\"")
+               return nil
+       }
+       urlList, err := metaDataService.GetExportedURLs(constant.AnyValue, 
constant.AnyValue, constant.AnyValue, constant.AnyValue)
+       if err != nil {
+               panic(err)
+       }
+       if len(urlList) == 0 {
+               return nil
+       }
+       for _, url := range urlList {
+               selectedUrl = url
+               // rest first
+               if url.Protocol == "rest" {
+                       break
+               }
+       }
+       return selectedUrl
+}
diff --git a/registry/options.go b/registry/options.go
new file mode 100644
index 000000000..af4011232
--- /dev/null
+++ b/registry/options.go
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package registry
+
+import (
+       "time"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/global"
+)
+
+type Options struct {
+       Registry *global.RegistryConfig
+}
+
+func DefaultOptions() *Options {
+       return &Options{Registry: global.DefaultRegistryConfig()}
+}
+
+type Option func(*Options)
+
+func WithEtcdV3() Option {
+       return func(opts *Options) {
+               // todo(DMwangnima): move etcdv3 to constant
+               opts.Registry.Protocol = "etcdv3"
+       }
+}
+
+func WithNacos() Option {
+       return func(opts *Options) {
+               opts.Registry.Protocol = constant.NacosKey
+       }
+}
+
+func WithPolaris() Option {
+       return func(opts *Options) {
+               opts.Registry.Protocol = constant.PolarisKey
+       }
+}
+
+func WithXDS() Option {
+       return func(opts *Options) {
+               opts.Registry.Protocol = constant.XDSRegistryKey
+       }
+}
+
+func WithZookeeper() Option {
+       return func(opts *Options) {
+               // todo(DMwangnima): move zookeeper to constant
+               opts.Registry.Protocol = "zookeeper"
+       }
+}
+
+func WithTimeout(timeout time.Duration) Option {
+       return func(opts *Options) {
+               opts.Registry.Timeout = timeout.String()
+       }
+}
+
+func WithGroup(group string) Option {
+       return func(opts *Options) {
+               opts.Registry.Group = group
+       }
+}
+
+func WithNamespace(namespace string) Option {
+       return func(opts *Options) {
+               opts.Registry.Namespace = namespace
+       }
+}
+
+func WithTTL(ttl time.Duration) Option {
+       return func(opts *Options) {
+               opts.Registry.TTL = ttl.String()
+       }
+}
+
+func WithAddress(address string) Option {
+       return func(opts *Options) {
+               opts.Registry.Address = address
+       }
+}
+
+func WithUsername(name string) Option {
+       return func(opts *Options) {
+               opts.Registry.Username = name
+       }
+}
+
+func WithPassword(password string) Option {
+       return func(opts *Options) {
+               opts.Registry.Password = password
+       }
+}
+
+func WithSimplified() Option {
+       return func(opts *Options) {
+               opts.Registry.Simplified = true
+       }
+}
+
+func WithPreferred() Option {
+       return func(opts *Options) {
+               opts.Registry.Preferred = true
+       }
+}
+
+func WithZone(zone string) Option {
+       return func(opts *Options) {
+               opts.Registry.Zone = zone
+       }
+}
+
+func WithWeight(weight int64) Option {
+       return func(opts *Options) {
+               opts.Registry.Weight = weight
+       }
+}
+
+func WithParams(params map[string]string) Option {
+       return func(opts *Options) {
+               opts.Registry.Params = params
+       }
+}
+
+func WithRegisterServiceAndInterface() Option {
+       return func(opts *Options) {
+               opts.Registry.RegistryType = constant.RegistryTypeAll
+       }
+}
+
+func WithRegisterInterface() Option {
+       return func(opts *Options) {
+               opts.Registry.RegistryType = constant.RegistryTypeInterface
+       }
+}
+
+func WithoutUseAsMetaReport() Option {
+       return func(opts *Options) {
+               opts.Registry.UseAsMetaReport = false
+       }
+}
+
+func WithoutUseAsConfigCenter() Option {
+       return func(opts *Options) {
+               opts.Registry.UseAsConfigCenter = false
+       }
+}
diff --git a/server/action.go b/server/action.go
index 84f9e07ec..6f9332175 100644
--- a/server/action.go
+++ b/server/action.go
@@ -19,7 +19,6 @@ package server
 
 import (
        "container/list"
-
        "fmt"
        "net/url"
        "os"
@@ -29,8 +28,6 @@ import (
 )
 
 import (
-       "github.com/creasty/defaults"
-
        "github.com/dubbogo/gost/log/logger"
        gxnet "github.com/dubbogo/gost/net"
 
@@ -41,58 +38,22 @@ import (
 
 import (
        "dubbo.apache.org/dubbo-go/v3/common"
-       commonCfg "dubbo.apache.org/dubbo-go/v3/common/config"
        "dubbo.apache.org/dubbo-go/v3/common/constant"
        "dubbo.apache.org/dubbo-go/v3/common/extension"
        "dubbo.apache.org/dubbo-go/v3/config"
+       "dubbo.apache.org/dubbo-go/v3/global"
+       "dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
+       "dubbo.apache.org/dubbo-go/v3/protocol"
        "dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper"
 )
 
 // Prefix returns dubbo.service.${InterfaceName}.
-func (s *ServerOptions) Prefix() string {
-       return strings.Join([]string{constant.ServiceConfigPrefix, s.Id}, ".")
+func (svcOpts *ServiceOptions) Prefix() string {
+       return strings.Join([]string{constant.ServiceConfigPrefix, svcOpts.Id}, 
".")
 }
 
-func (s *ServerOptions) Init(opts ...ServerOption) error {
-       for _, opt := range opts {
-               opt(s)
-       }
-       if err := defaults.Set(s); err != nil {
-               return err
-       }
-       for _, opt := range opts {
-               opt(s)
-       }
-
-       srv := s.Server
-
-       s.exported = atomic.NewBool(false)
-
-       application := s.Application
-       if application != nil {
-               s.applicationCompat = compatApplicationConfig(application)
-               if err := s.applicationCompat.Init(); err != nil {
-                       return err
-               }
-               s.metadataType = s.applicationCompat.MetadataType
-               if srv.Group == "" {
-                       srv.Group = s.applicationCompat.Group
-               }
-               if srv.Version == "" {
-                       srv.Version = s.applicationCompat.Version
-               }
-       }
-       s.unexported = atomic.NewBool(false)
-       err := s.check()
-       if err != nil {
-               panic(err)
-       }
-       s.Export = true
-       return commonCfg.Verify(s)
-}
-
-func (s *ServerOptions) check() error {
-       srv := s.Server
+func (svcOpts *ServiceOptions) check() error {
+       srv := svcOpts.Service
        // check if the limiter has been imported
        if srv.TpsLimiter != "" {
                _, err := extension.GetTpsLimiter(srv.TpsLimiter)
@@ -116,33 +77,33 @@ func (s *ServerOptions) check() error {
        if srv.TpsLimitInterval != "" {
                tpsLimitInterval, err := strconv.ParseInt(srv.TpsLimitInterval, 
0, 0)
                if err != nil {
-                       return fmt.Errorf("[ServiceConfig] Cannot parse the 
configuration tps.limit.interval for service %s, please check your 
configuration", srv.Interface)
+                       return fmt.Errorf("[ServiceConfig] Cannot parse the 
configuration tps.limit.interval for service %svcOpts, please check your 
configuration", srv.Interface)
                }
                if tpsLimitInterval < 0 {
-                       return fmt.Errorf("[ServiceConfig] The configuration 
tps.limit.interval for service %s must be positive, please check your 
configuration", srv.Interface)
+                       return fmt.Errorf("[ServiceConfig] The configuration 
tps.limit.interval for service %svcOpts must be positive, please check your 
configuration", srv.Interface)
                }
        }
 
        if srv.TpsLimitRate != "" {
                tpsLimitRate, err := strconv.ParseInt(srv.TpsLimitRate, 0, 0)
                if err != nil {
-                       return fmt.Errorf("[ServiceConfig] Cannot parse the 
configuration tps.limit.rate for service %s, please check your configuration", 
srv.Interface)
+                       return fmt.Errorf("[ServiceConfig] Cannot parse the 
configuration tps.limit.rate for service %svcOpts, please check your 
configuration", srv.Interface)
                }
                if tpsLimitRate < 0 {
-                       return fmt.Errorf("[ServiceConfig] The configuration 
tps.limit.rate for service %s must be positive, please check your 
configuration", srv.Interface)
+                       return fmt.Errorf("[ServiceConfig] The configuration 
tps.limit.rate for service %svcOpts must be positive, please check your 
configuration", srv.Interface)
                }
        }
        return nil
 }
 
 // InitExported will set exported as false atom bool
-func (s *ServerOptions) InitExported() {
-       s.exported = atomic.NewBool(false)
+func (svcOpts *ServiceOptions) InitExported() {
+       svcOpts.exported = atomic.NewBool(false)
 }
 
 // IsExport will return whether the service config is exported or not
-func (s *ServerOptions) IsExport() bool {
-       return s.exported.Load()
+func (svcOpts *ServiceOptions) IsExport() bool {
+       return svcOpts.exported.Load()
 }
 
 // Get Random Port
@@ -163,66 +124,61 @@ func getRandomPort(protocolConfigs 
[]*config.ProtocolConfig) *list.List {
        return ports
 }
 
-func (s *ServerOptions) ExportWithoutInfo() error {
-       return s.export(nil)
+func (svcOpts *ServiceOptions) ExportWithoutInfo() error {
+       return svcOpts.export(nil)
 }
 
-func (s *ServerOptions) ExportWithInfo(info *ServiceInfo) error {
-       return s.export(info)
+func (svcOpts *ServiceOptions) ExportWithInfo(info *ServiceInfo) error {
+       return svcOpts.export(info)
 }
 
-func (s *ServerOptions) export(info *ServiceInfo) error {
-       srv := s.Server
+func (svcOpts *ServiceOptions) export(info *ServiceInfo) error {
+       srv := svcOpts.Service
 
-       var methodInfos []MethodInfo
-       var methods string
        if info != nil {
                srv.Interface = info.InterfaceName
-               methodInfos = info.Methods
-               s.Id = info.InterfaceName
-               s.info = info
+               svcOpts.Id = info.InterfaceName
+               svcOpts.info = info
        }
-       // TODO: delay export
-       if s.unexported != nil && s.unexported.Load() {
+       // TODO: delay needExport
+       if svcOpts.unexported != nil && svcOpts.unexported.Load() {
                err := perrors.Errorf("The service %v has already unexported!", 
srv.Interface)
                logger.Errorf(err.Error())
                return err
        }
-       if s.exported != nil && s.exported.Load() {
+       if svcOpts.exported != nil && svcOpts.exported.Load() {
                logger.Warnf("The service %v has already exported!", 
srv.Interface)
                return nil
        }
 
        regUrls := make([]*common.URL, 0)
        if !srv.NotRegister {
-               regUrls = config.LoadRegistries(srv.RegistryIDs, 
s.registriesCompat, common.PROVIDER)
+               regUrls = config.LoadRegistries(srv.RegistryIDs, 
svcOpts.registriesCompat, common.PROVIDER)
        }
 
-       urlMap := s.getUrlMap()
-       protocolConfigs := loadProtocol(srv.ProtocolIDs, s.protocolCompat)
+       urlMap := svcOpts.getUrlMap()
+       protocolConfigs := loadProtocol(srv.ProtocolIDs, 
svcOpts.protocolsCompat)
        if len(protocolConfigs) == 0 {
-               logger.Warnf("The service %v's '%v' protocols don't has right 
protocolConfigs, Please check your configuration center and transfer protocol 
", srv.Interface, srv.ProtocolIDs)
+               logger.Warnf("The service %v'svcOpts '%v' protocols don't has 
right protocolConfigs, Please check your configuration center and transfer 
protocol ", srv.Interface, srv.ProtocolIDs)
                return nil
        }
 
+       var invoker protocol.Invoker
        ports := getRandomPort(protocolConfigs)
        nextPort := ports.Front()
-       proxyFactory := extension.GetProxyFactory(s.ProxyFactoryKey)
+       proxyFactory := extension.GetProxyFactory(svcOpts.ProxyFactoryKey)
        for _, proto := range protocolConfigs {
-               if info != nil {
-                       for _, info := range methodInfos {
-                               methods += info.Name + ","
-                       }
-               } else {
-                       // registry the service reflect
-                       var err error
-                       methods, err = 
common.ServiceMap.Register(srv.Interface, proto.Name, srv.Group, srv.Version, 
s.rpcService)
-                       if err != nil {
-                               formatErr := perrors.Errorf("The service %v 
export the protocol %v error! Error message is %v.",
-                                       srv.Interface, proto.Name, err.Error())
-                               logger.Errorf(formatErr.Error())
-                               return formatErr
-                       }
+               // *important* Register should have been replaced by processing 
of ServiceInfo.
+               // but many modules like metadata need to make use of 
information from ServiceMap.
+               // todo(DMwangnimg): finish replacing procedure
+
+               // registry the service reflect
+               methods, err := common.ServiceMap.Register(srv.Interface, 
proto.Name, srv.Group, srv.Version, svcOpts.rpcService)
+               if err != nil {
+                       formatErr := perrors.Errorf("The service %v needExport 
the protocol %v error! Error message is %v.",
+                               srv.Interface, proto.Name, err.Error())
+                       logger.Errorf(formatErr.Error())
+                       return formatErr
                }
 
                port := proto.Port
@@ -236,12 +192,13 @@ func (s *ServerOptions) export(info *ServiceInfo) error {
                        common.WithIp(proto.Ip),
                        common.WithPort(port),
                        common.WithParams(urlMap),
-                       common.WithParamsValue(constant.BeanNameKey, s.Id),
+                       common.WithParamsValue(constant.BeanNameKey, 
svcOpts.Id),
                        //common.WithParamsValue(constant.SslEnabledKey, 
strconv.FormatBool(config.GetSslEnabled())),
                        common.WithMethods(strings.Split(methods, ",")),
-                       common.WithMethodInfos(methodInfos),
+                       // todo(DMwangnima): remove this
+                       common.WithAttribute(constant.ServiceInfoKey, info),
                        common.WithToken(srv.Token),
-                       common.WithParamsValue(constant.MetadataTypeKey, 
s.metadataType),
+                       common.WithParamsValue(constant.MetadataTypeKey, 
svcOpts.metadataType),
                        // fix https://github.com/apache/dubbo-go/issues/2176
                        common.WithParamsValue(constant.MaxServerSendMsgSize, 
proto.MaxServerSendMsgSize),
                        common.WithParamsValue(constant.MaxServerRecvMsgSize, 
proto.MaxServerRecvMsgSize),
@@ -251,50 +208,61 @@ func (s *ServerOptions) export(info *ServiceInfo) error {
                }
 
                // post process the URL to be exported
-               s.postProcessConfig(ivkURL)
-               // config post processor may set "export" to false
+               svcOpts.postProcessConfig(ivkURL)
+               // config post processor may set "needExport" to false
                if !ivkURL.GetParamBool(constant.ExportKey, true) {
                        return nil
                }
 
                if len(regUrls) > 0 {
-                       s.cacheMutex.Lock()
-                       if s.cacheProtocol == nil {
+                       svcOpts.cacheMutex.Lock()
+                       if svcOpts.cacheProtocol == nil {
                                logger.Debugf(fmt.Sprintf("First load the 
registry protocol, url is {%v}!", ivkURL))
-                               s.cacheProtocol = 
extension.GetProtocol(constant.RegistryProtocol)
+                               svcOpts.cacheProtocol = 
extension.GetProtocol(constant.RegistryProtocol)
                        }
-                       s.cacheMutex.Unlock()
+                       svcOpts.cacheMutex.Unlock()
 
                        for _, regUrl := range regUrls {
                                setRegistrySubURL(ivkURL, regUrl)
-                               invoker := proxyFactory.GetInvoker(regUrl)
-                               exporter := s.cacheProtocol.Export(invoker)
+                               if info == nil {
+                                       invoker = 
proxyFactory.GetInvoker(regUrl)
+                               } else {
+                                       invoker = newInfoInvoker(regUrl, info, 
svcOpts.rpcService)
+                               }
+                               exporter := 
svcOpts.cacheProtocol.Export(invoker)
                                if exporter == nil {
                                        return 
perrors.New(fmt.Sprintf("Registry protocol new exporter error, registry is 
{%v}, url is {%v}", regUrl, ivkURL))
                                }
-                               s.exporters = append(s.exporters, exporter)
+                               svcOpts.exporters = append(svcOpts.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)
+                                       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 = %s", err)
+                                       logger.Warnf("SetMetadataServiceURL 
error = %svcOpts", err)
                                }
                        }
-                       invoker := proxyFactory.GetInvoker(ivkURL)
+                       if info == nil {
+                               invoker = proxyFactory.GetInvoker(ivkURL)
+                       } else {
+                               invoker = newInfoInvoker(ivkURL, info, 
svcOpts.rpcService)
+                       }
                        exporter := 
extension.GetProtocol(protocolwrapper.FILTER).Export(invoker)
                        if exporter == nil {
                                return perrors.New(fmt.Sprintf("Filter protocol 
without registry new exporter error, url is {%v}", ivkURL))
                        }
-                       s.exporters = append(s.exporters, exporter)
+                       svcOpts.exporters = append(svcOpts.exporters, exporter)
                }
                publishServiceDefinition(ivkURL)
+               // this protocol would be destroyed in graceful_shutdown
+               // please refer to 
(https://github.com/apache/dubbo-go/issues/2429)
+               graceful_shutdown.RegisterProtocol(proto.Name)
        }
-       s.exported.Store(true)
+       svcOpts.exported.Store(true)
        return nil
 }
 
@@ -318,35 +286,35 @@ func loadProtocol(protocolIds []string, protocols 
map[string]*config.ProtocolCon
 }
 
 // Unexport will call unexport of all exporters service config exported
-func (s *ServerOptions) Unexport() {
-       if !s.exported.Load() {
+func (svcOpts *ServiceOptions) Unexport() {
+       if !svcOpts.exported.Load() {
                return
        }
-       if s.unexported.Load() {
+       if svcOpts.unexported.Load() {
                return
        }
 
        func() {
-               s.exportersLock.Lock()
-               defer s.exportersLock.Unlock()
-               for _, exporter := range s.exporters {
+               svcOpts.exportersLock.Lock()
+               defer svcOpts.exportersLock.Unlock()
+               for _, exporter := range svcOpts.exporters {
                        exporter.UnExport()
                }
-               s.exporters = nil
+               svcOpts.exporters = nil
        }()
 
-       s.exported.Store(false)
-       s.unexported.Store(true)
+       svcOpts.exported.Store(false)
+       svcOpts.unexported.Store(true)
 }
 
 // Implement only store the @s and return
-func (s *ServerOptions) Implement(rpcService common.RPCService) {
-       s.rpcService = rpcService
+func (svcOpts *ServiceOptions) Implement(rpcService common.RPCService) {
+       svcOpts.rpcService = rpcService
 }
 
-func (s *ServerOptions) getUrlMap() url.Values {
-       srv := s.Server
-       app := s.applicationCompat
+func (svcOpts *ServiceOptions) getUrlMap() url.Values {
+       srv := svcOpts.Service
+       app := svcOpts.applicationCompat
 
        urlMap := url.Values{}
        // first set user params
@@ -379,15 +347,15 @@ func (s *ServerOptions) getUrlMap() url.Values {
        urlMap.Set(constant.OwnerKey, app.Owner)
        urlMap.Set(constant.EnvironmentKey, app.Environment)
 
-       // filter
+       //filter
        var filters string
        if srv.Filter == "" {
                filters = constant.DefaultServiceFilters
        } else {
                filters = srv.Filter
        }
-       if s.adaptiveService {
-               filters += fmt.Sprintf(",%s", 
constant.AdaptiveServiceProviderFilterKey)
+       if svcOpts.adaptiveService {
+               filters += fmt.Sprintf(",%svcOpts", 
constant.AdaptiveServiceProviderFilterKey)
        }
        urlMap.Set(constant.ServiceFilterKey, filters)
 
@@ -409,8 +377,8 @@ func (s *ServerOptions) getUrlMap() url.Values {
        urlMap.Set(constant.ServiceAuthKey, srv.Auth)
        urlMap.Set(constant.ParameterSignatureEnableKey, srv.ParamSign)
 
-       // whether to export or not
-       urlMap.Set(constant.ExportKey, strconv.FormatBool(s.Export))
+       // whether to needExport or not
+       urlMap.Set(constant.ExportKey, strconv.FormatBool(svcOpts.needExport))
        urlMap.Set(constant.PIDKey, fmt.Sprintf("%d", os.Getpid()))
 
        for _, v := range srv.Methods {
@@ -431,10 +399,10 @@ func (s *ServerOptions) getUrlMap() url.Values {
 }
 
 // GetExportedUrls will return the url in service config's exporter
-func (s *ServerOptions) GetExportedUrls() []*common.URL {
-       if s.exported.Load() {
+func (svcOpts *ServiceOptions) GetExportedUrls() []*common.URL {
+       if svcOpts.exported.Load() {
                var urls []*common.URL
-               for _, exporter := range s.exporters {
+               for _, exporter := range svcOpts.exporters {
                        urls = append(urls, exporter.GetInvoker().GetURL())
                }
                return urls
@@ -443,7 +411,7 @@ func (s *ServerOptions) GetExportedUrls() []*common.URL {
 }
 
 // postProcessConfig asks registered ConfigPostProcessor to post-process the 
current ServiceConfig.
-func (s *ServerOptions) postProcessConfig(url *common.URL) {
+func (svcOpts *ServiceOptions) postProcessConfig(url *common.URL) {
        for _, p := range extension.GetConfigPostProcessors() {
                p.PostProcessServiceConfig(url)
        }
@@ -463,3 +431,25 @@ func publishServiceDefinition(url *common.URL) {
                remoteMetadataService.PublishServiceDefinition(url)
        }
 }
+
+// todo(DMwangnima): think about moving this function to a common place(e.g. 
/common/config)
+func getRegistryIds(registries map[string]*global.RegistryConfig) []string {
+       ids := make([]string, 0)
+       for key := range registries {
+               ids = append(ids, key)
+       }
+       return removeDuplicateElement(ids)
+}
+
+// removeDuplicateElement remove duplicate element
+func removeDuplicateElement(items []string) []string {
+       result := make([]string, 0, len(items))
+       temp := map[string]struct{}{}
+       for _, item := range items {
+               if _, ok := temp[item]; !ok && item != "" {
+                       temp[item] = struct{}{}
+                       result = append(result, item)
+               }
+       }
+       return result
+}
diff --git a/server/compat.go b/server/compat.go
index f22c8cc9f..9e34254d3 100644
--- a/server/compat.go
+++ b/server/compat.go
@@ -77,3 +77,14 @@ func compatMethodConfig(c *global.MethodConfig) 
*config.MethodConfig {
                RequestTimeout:              c.RequestTimeout,
        }
 }
+
+func compatProtocolConfig(c *global.ProtocolConfig) *config.ProtocolConfig {
+       return &config.ProtocolConfig{
+               Name:                 c.Name,
+               Ip:                   c.Ip,
+               Port:                 c.Port,
+               Params:               c.Params,
+               MaxServerSendMsgSize: c.MaxServerSendMsgSize,
+               MaxServerRecvMsgSize: c.MaxServerRecvMsgSize,
+       }
+}
diff --git a/server/options.go b/server/options.go
index 36b75a8ac..6dff299cd 100644
--- a/server/options.go
+++ b/server/options.go
@@ -17,25 +17,222 @@
 
 package server
 
+import (
+       "strconv"
+       "sync"
+       "time"
+)
+
+import (
+       "github.com/creasty/defaults"
+
+       "github.com/dubbogo/gost/log/logger"
+
+       perrors "github.com/pkg/errors"
+
+       "go.uber.org/atomic"
+)
+
 import (
        "dubbo.apache.org/dubbo-go/v3/common"
+       commonCfg "dubbo.apache.org/dubbo-go/v3/common/config"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
        "dubbo.apache.org/dubbo-go/v3/config"
+       aslimiter "dubbo.apache.org/dubbo-go/v3/filter/adaptivesvc/limiter"
        "dubbo.apache.org/dubbo-go/v3/global"
+       "dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
        "dubbo.apache.org/dubbo-go/v3/protocol"
-       "go.uber.org/atomic"
-       "sync"
+       "dubbo.apache.org/dubbo-go/v3/registry"
 )
 
 type ServerOptions struct {
+       Provider    *global.ProviderConfig
+       Application *global.ApplicationConfig
+       Registries  map[string]*global.RegistryConfig
+       Protocols   map[string]*global.ProtocolConfig
+       Tracings    map[string]*global.TracingConfig
+       Shutdown    *global.ShutdownConfig
+
+       providerCompat *config.ProviderConfig
+}
+
+func defaultServerOptions() *ServerOptions {
+       return &ServerOptions{
+               Application: global.DefaultApplicationConfig(),
+               Provider:    global.DefaultProviderConfig(),
+               Shutdown:    global.DefaultShutdownConfig(),
+       }
+}
+
+// todo(DMwangnima): think about the timing to initialize Registry, Protocol, 
Tracing
+func (srvOpts *ServerOptions) init(opts ...ServerOption) error {
+       for _, opt := range opts {
+               opt(srvOpts)
+       }
+       if err := defaults.Set(srvOpts); err != nil {
+               return err
+       }
+
+       prov := srvOpts.Provider
+
+       prov.RegistryIDs = commonCfg.TranslateIds(prov.RegistryIDs)
+       if len(prov.RegistryIDs) <= 0 {
+               prov.RegistryIDs = getRegistryIds(srvOpts.Registries)
+       }
+
+       prov.ProtocolIDs = commonCfg.TranslateIds(prov.ProtocolIDs)
+
+       if prov.TracingKey == "" && len(srvOpts.Tracings) > 0 {
+               for key := range srvOpts.Tracings {
+                       prov.TracingKey = key
+                       break
+               }
+       }
+
+       if err := commonCfg.Verify(prov); err != nil {
+               return err
+       }
+
+       // enable adaptive service verbose
+       if prov.AdaptiveServiceVerbose {
+               if !prov.AdaptiveService {
+                       return perrors.Errorf("The adaptive service is 
disabled, " +
+                               "adaptive service verbose should be disabled 
either.")
+               }
+               logger.Infof("adaptive service verbose is enabled.")
+               logger.Debugf("debug-level info could be shown.")
+               aslimiter.Verbose = true
+       }
+
+       // init graceful_shutdown
+       
graceful_shutdown.Init(graceful_shutdown.WithShutdown_Config(srvOpts.Shutdown))
+
+       return nil
+}
+
+type ServerOption func(*ServerOptions)
+
+// ---------- For user ----------
+
+// todo(DMwangnima): change Filter Option like Cluster and LoadBalance
+func WithServer_Filter(filter string) ServerOption {
+       return func(opts *ServerOptions) {
+               opts.Provider.Filter = filter
+       }
+}
+
+// todo(DMwangnima): think about a more ideal configuration style
+func WithServer_RegistryIDs(registryIDs []string) ServerOption {
+       return func(opts *ServerOptions) {
+               opts.Provider.RegistryIDs = registryIDs
+       }
+}
+
+func WithServer_Registry(key string, opts ...registry.Option) ServerOption {
+       regOpts := registry.DefaultOptions()
+       for _, opt := range opts {
+               opt(regOpts)
+       }
+
+       return func(srvOpts *ServerOptions) {
+               if srvOpts.Registries == nil {
+                       srvOpts.Registries = 
make(map[string]*global.RegistryConfig)
+               }
+               srvOpts.Registries[key] = regOpts.Registry
+       }
+}
+
+// todo(DMwangnima): think about a more ideal configuration style
+func WithServer_ProtocolIDs(protocolIDs []string) ServerOption {
+       return func(opts *ServerOptions) {
+               opts.Provider.ProtocolIDs = protocolIDs
+       }
+}
+
+func WithServer_Protocol(key string, opts ...protocol.Option) ServerOption {
+       proOpts := protocol.DefaultOptions()
+       for _, opt := range opts {
+               opt(proOpts)
+       }
+
+       return func(srvOpts *ServerOptions) {
+               if srvOpts.Protocols == nil {
+                       srvOpts.Protocols = 
make(map[string]*global.ProtocolConfig)
+               }
+               srvOpts.Protocols[key] = proOpts.Protocol
+       }
+}
+
+func WithServer_TracingKey(tracingKey string) ServerOption {
+       return func(opts *ServerOptions) {
+               opts.Provider.TracingKey = tracingKey
+       }
+}
+
+// todo(DMwangnima): this configuration would be used by filter/hystrix
+// think about a more ideal way to configure
+func WithServer_FilterConf(conf interface{}) ServerOption {
+       return func(opts *ServerOptions) {
+               opts.Provider.FilterConf = conf
+       }
+}
+
+func WithServer_AdaptiveService() ServerOption {
+       return func(opts *ServerOptions) {
+               opts.Provider.AdaptiveService = true
+       }
+}
+
+func WithServer_AdaptiveServiceVerbose() ServerOption {
+       return func(opts *ServerOptions) {
+               opts.Provider.AdaptiveServiceVerbose = true
+       }
+}
+
+// ========== For framework ==========
+// These functions should not be invoked by users
+
+func SetServer_Application(application *global.ApplicationConfig) ServerOption 
{
+       return func(opts *ServerOptions) {
+               opts.Application = application
+       }
+}
+
+func SetServer_Registries(regs map[string]*global.RegistryConfig) ServerOption 
{
+       return func(opts *ServerOptions) {
+               opts.Registries = regs
+       }
+}
+
+func SetServer_Protocols(pros map[string]*global.ProtocolConfig) ServerOption {
+       return func(opts *ServerOptions) {
+               opts.Protocols = pros
+       }
+}
+
+func SetServer_Tracings(tras map[string]*global.TracingConfig) ServerOption {
+       return func(opts *ServerOptions) {
+               opts.Tracings = tras
+       }
+}
+
+func SetServer_Shutdown(shutdown *global.ShutdownConfig) ServerOption {
+       return func(opts *ServerOptions) {
+               opts.Shutdown = shutdown
+       }
+}
+
+type ServiceOptions struct {
        Application *global.ApplicationConfig
        Provider    *global.ProviderConfig
-       Server      *global.ServiceConfig
+       Service     *global.ServiceConfig
        Registries  map[string]*global.RegistryConfig
+       Protocols   map[string]*global.ProtocolConfig
 
        Id              string
        unexported      *atomic.Bool
        exported        *atomic.Bool
-       Export          bool
+       needExport      bool
        metadataType    string
        info            *ServiceInfo
        ProxyFactoryKey string
@@ -49,127 +246,306 @@ type ServerOptions struct {
        methodsCompat     []*config.MethodConfig
        applicationCompat *config.ApplicationConfig
        registriesCompat  map[string]*config.RegistryConfig
-       protocolCompat    map[string]*config.ProtocolConfig
+       protocolsCompat   map[string]*config.ProtocolConfig
 }
 
-func defaultServerOptions() *ServerOptions {
-       return &ServerOptions{
-               Provider: global.DefaultProviderConfig(),
+func defaultServiceOptions() *ServiceOptions {
+       return &ServiceOptions{
+               Service:     global.DefaultServiceConfig(),
+               Application: global.DefaultApplicationConfig(),
+               unexported:  atomic.NewBool(false),
+               exported:    atomic.NewBool(false),
+               needExport:  true,
        }
 }
 
-func (srvOpts *ServerOptions) init(opts ...ServerOption) error {
+func (svcOpts *ServiceOptions) init(opts ...ServiceOption) error {
        for _, opt := range opts {
-               opt(srvOpts)
+               opt(svcOpts)
        }
-       return nil
+       if err := defaults.Set(svcOpts); err != nil {
+               return err
+       }
+
+       srv := svcOpts.Service
+
+       svcOpts.exported = atomic.NewBool(false)
+
+       application := svcOpts.Application
+       if application != nil {
+               svcOpts.applicationCompat = compatApplicationConfig(application)
+               if err := svcOpts.applicationCompat.Init(); err != nil {
+                       return err
+               }
+               // todo(DMwangnima): make this clearer
+               // this statement is responsible for setting 
rootConfig.Application
+               // since many modules would retrieve this information directly.
+               config.GetRootConfig().Application = svcOpts.applicationCompat
+               svcOpts.metadataType = svcOpts.applicationCompat.MetadataType
+               if srv.Group == "" {
+                       srv.Group = svcOpts.applicationCompat.Group
+               }
+               if srv.Version == "" {
+                       srv.Version = svcOpts.applicationCompat.Version
+               }
+       }
+       svcOpts.unexported = atomic.NewBool(false)
+
+       // initialize Registries
+       if len(srv.RCRegistriesMap) == 0 {
+               srv.RCRegistriesMap = svcOpts.Registries
+       }
+       if len(srv.RCRegistriesMap) > 0 {
+               svcOpts.registriesCompat = 
make(map[string]*config.RegistryConfig)
+               for key, reg := range srv.RCRegistriesMap {
+                       svcOpts.registriesCompat[key] = 
compatRegistryConfig(reg)
+                       if err := svcOpts.registriesCompat[key].Init(); err != 
nil {
+                               return err
+                       }
+               }
+       }
+
+       // initialize Protocols
+       if len(srv.RCProtocolsMap) == 0 {
+               srv.RCProtocolsMap = svcOpts.Protocols
+       }
+       if len(srv.RCProtocolsMap) > 0 {
+               svcOpts.protocolsCompat = 
make(map[string]*config.ProtocolConfig)
+               for key, pro := range srv.RCProtocolsMap {
+                       svcOpts.protocolsCompat[key] = compatProtocolConfig(pro)
+                       if err := svcOpts.protocolsCompat[key].Init(); err != 
nil {
+                               return err
+                       }
+               }
+       }
+
+       srv.RegistryIDs = commonCfg.TranslateIds(srv.RegistryIDs)
+       if len(srv.RegistryIDs) <= 0 {
+               srv.RegistryIDs = svcOpts.Provider.RegistryIDs
+       }
+       if srv.RegistryIDs == nil || len(srv.RegistryIDs) <= 0 {
+               srv.NotRegister = true
+       }
+
+       srv.ProtocolIDs = commonCfg.TranslateIds(srv.ProtocolIDs)
+       if len(srv.ProtocolIDs) <= 0 {
+               srv.ProtocolIDs = svcOpts.Provider.ProtocolIDs
+       }
+       if len(srv.ProtocolIDs) <= 0 {
+               for name := range svcOpts.Protocols {
+                       srv.ProtocolIDs = append(srv.ProtocolIDs, name)
+               }
+       }
+
+       if srv.TracingKey == "" {
+               srv.TracingKey = svcOpts.Provider.TracingKey
+       }
+
+       err := svcOpts.check()
+       if err != nil {
+               panic(err)
+       }
+       svcOpts.needExport = true
+       return commonCfg.Verify(svcOpts)
 }
 
-type ServerOption func(*ServerOptions)
+type ServiceOption func(*ServiceOptions)
 
 // ---------- For user ----------
 
-func WithRegistryIDs(registryIDs []string) ServerOption {
-       return func(cfg *ServerOptions) {
+// todo(DMwangnima): think about a more ideal configuration style
+func WithRegistryIDs(registryIDs []string) ServiceOption {
+       return func(cfg *ServiceOptions) {
                if len(registryIDs) <= 0 {
-                       cfg.Server.RegistryIDs = registryIDs
+                       cfg.Service.RegistryIDs = registryIDs
                }
        }
 }
 
-func WithFilter(filter string) ServerOption {
-       return func(cfg *ServerOptions) {
-               cfg.Server.Filter = filter
+// todo(DMwangnima): change Filter Option like Cluster and LoadBalance
+func WithFilter(filter string) ServiceOption {
+       return func(cfg *ServiceOptions) {
+               cfg.Service.Filter = filter
        }
 }
 
-func WithProtocolIDs(protocolIDs []string) ServerOption {
-       return func(cfg *ServerOptions) {
+// todo(DMwangnima): think about a more ideal configuration style
+func WithProtocolIDs(protocolIDs []string) ServiceOption {
+       return func(cfg *ServiceOptions) {
                if len(protocolIDs) <= 0 {
-                       cfg.Server.ProtocolIDs = protocolIDs
+                       cfg.Service.ProtocolIDs = protocolIDs
                }
        }
 }
 
-func WithTracingKey(tracingKey string) ServerOption {
-       return func(cfg *ServerOptions) {
-               cfg.Server.TracingKey = tracingKey
+func WithTracingKey(tracingKey string) ServiceOption {
+       return func(cfg *ServiceOptions) {
+               cfg.Service.TracingKey = tracingKey
+       }
+}
+
+// ========== LoadBalance Strategy ==========
+
+func WithLoadBalanceConsistentHashing() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Loadbalance = 
constant.LoadBalanceKeyConsistentHashing
        }
 }
 
-func WithLoadBalance(loadBalance string) ServerOption {
-       return func(cfg *ServerOptions) {
-               cfg.Server.Loadbalance = loadBalance
+func WithLoadBalanceLeastActive() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Loadbalance = constant.LoadBalanceKeyLeastActive
        }
 }
 
-func WithWarmUp(warmUp string) ServerOption {
-       return func(cfg *ServerOptions) {
-               cfg.Server.Warmup = warmUp
+func WithLoadBalanceRandom() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Loadbalance = constant.LoadBalanceKeyRandom
        }
 }
 
-func WithCluster(cluster string) ServerOption {
-       return func(cfg *ServerOptions) {
-               cfg.Server.Cluster = cluster
+func WithLoadBalanceRoundRobin() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Loadbalance = constant.LoadBalanceKeyRoundRobin
        }
 }
 
-func WithGroup(group string) ServerOption {
-       return func(cfg *ServerOptions) {
-               cfg.Server.Group = group
+func WithLoadBalanceP2C() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Loadbalance = constant.LoadBalanceKeyP2C
        }
 }
 
-func WithVersion(version string) ServerOption {
-       return func(cfg *ServerOptions) {
-               cfg.Server.Version = version
+func WithLoadBalanceXDSRingHash() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Loadbalance = constant.LoadBalanceKeyLeastActive
        }
 }
 
-func WithSerialization(serialization string) ServerOption {
-       return func(cfg *ServerOptions) {
-               cfg.Server.Serialization = serialization
+// warmUp is in seconds
+func WithWarmUp(warmUp time.Duration) ServiceOption {
+       return func(opts *ServiceOptions) {
+               warmUpSec := int(warmUp / time.Second)
+               opts.Service.Warmup = strconv.Itoa(warmUpSec)
        }
 }
 
-func WithNotRegister(notRegister bool) ServerOption {
-       return func(cfg *ServerOptions) {
-               cfg.Server.NotRegister = notRegister
+// ========== Cluster Strategy ==========
+
+func WithClusterAvailable() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Cluster = constant.ClusterKeyAvailable
        }
 }
 
-// ----------From framework----------
+func WithClusterBroadcast() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Cluster = constant.ClusterKeyBroadcast
+       }
+}
 
-func WithApplicationConfig(opts ...global.ApplicationOption) ServerOption {
-       appCfg := new(global.ApplicationConfig)
-       for _, opt := range opts {
-               opt(appCfg)
+func WithClusterFailBack() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Cluster = constant.ClusterKeyFailback
        }
+}
 
-       return func(opts *ServerOptions) {
-               opts.Application = appCfg
+func WithClusterFailFast() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Cluster = constant.ClusterKeyFailfast
        }
 }
 
-func WithProviderConfig(opts ...global.ProviderOption) ServerOption {
-       providerCfg := new(global.ProviderConfig)
-       for _, opt := range opts {
-               opt(providerCfg)
+func WithClusterFailOver() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Cluster = constant.ClusterKeyFailover
        }
+}
 
-       return func(opts *ServerOptions) {
-               opts.Provider = providerCfg
+func WithClusterFailSafe() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Cluster = constant.ClusterKeyFailsafe
        }
 }
 
-func WithServiceConfig(opts ...global.ServiceOption) ServerOption {
-       serviceCfg := new(global.ServiceConfig)
-       for _, opt := range opts {
-               opt(serviceCfg)
+func WithClusterForking() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Cluster = constant.ClusterKeyForking
        }
+}
 
-       return func(opts *ServerOptions) {
-               opts.Server = serviceCfg
+func WithClusterZoneAware() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Cluster = constant.ClusterKeyZoneAware
+       }
+}
+
+func WithClusterAdaptiveService() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Cluster = constant.ClusterKeyAdaptiveService
+       }
+}
+
+func WithGroup(group string) ServiceOption {
+       return func(cfg *ServiceOptions) {
+               cfg.Service.Group = group
+       }
+}
+
+func WithVersion(version string) ServiceOption {
+       return func(cfg *ServiceOptions) {
+               cfg.Service.Version = version
+       }
+}
+
+func WithJSON() ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Serialization = constant.JSONSerialization
+       }
+}
+
+// WithToken should be used with WithFilter("token")
+func WithToken(token string) ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service.Token = token
+       }
+}
+
+func WithNotRegister() ServiceOption {
+       return func(cfg *ServiceOptions) {
+               cfg.Service.NotRegister = true
+       }
+}
+
+// ----------For framework----------
+// These functions should not be invoked by users
+
+func SetApplication(application *global.ApplicationConfig) ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Application = application
+       }
+}
+
+func SetProvider(provider *global.ProviderConfig) ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Provider = provider
+       }
+}
+
+func SetService(service *global.ServiceConfig) ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Service = service
+       }
+}
+
+func SetRegistries(regs map[string]*global.RegistryConfig) ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Registries = regs
+       }
+}
+
+func SetProtocols(pros map[string]*global.ProtocolConfig) ServiceOption {
+       return func(opts *ServiceOptions) {
+               opts.Protocols = pros
        }
 }
diff --git a/server/server.go b/server/server.go
index 763af3837..3cbcd8467 100644
--- a/server/server.go
+++ b/server/server.go
@@ -19,7 +19,18 @@ package server
 
 import (
        "context"
+       "fmt"
+)
+
+import (
+       "github.com/pkg/errors"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/metadata"
        "dubbo.apache.org/dubbo-go/v3/protocol"
+       registry_exposed "dubbo.apache.org/dubbo-go/v3/registry/exposed_tmp"
 )
 
 type Server struct {
@@ -37,14 +48,114 @@ type ServiceInfo struct {
        Meta          map[string]interface{}
 }
 
+type infoInvoker struct {
+       url       *common.URL
+       base      *protocol.BaseInvoker
+       info      *ServiceInfo
+       svc       common.RPCService
+       methodMap map[string]*MethodInfo
+}
+
+func (ii *infoInvoker) init() {
+       url := ii.base.GetURL()
+       if url.SubURL != nil {
+               url = url.SubURL
+       }
+       ii.url = url
+       methodMap := make(map[string]*MethodInfo)
+       for i := range ii.info.Methods {
+               methodMap[ii.info.Methods[i].Name] = &ii.info.Methods[i]
+       }
+       ii.methodMap = methodMap
+}
+
+func (ii *infoInvoker) GetURL() *common.URL {
+       return ii.base.GetURL()
+}
+
+func (ii *infoInvoker) IsAvailable() bool {
+       return ii.base.IsAvailable()
+}
+
+func (ii *infoInvoker) Destroy() {
+       ii.base.Destroy()
+}
+
+func (ii *infoInvoker) Invoke(ctx context.Context, invocation 
protocol.Invocation) protocol.Result {
+       name := invocation.MethodName()
+       args := invocation.Arguments()
+       result := new(protocol.RPCResult)
+       if method, ok := ii.methodMap[name]; ok {
+               res, err := method.MethodFunc(ctx, args, ii.svc)
+               result.SetResult(res)
+               result.SetError(err)
+               return result
+       }
+       result.SetError(fmt.Errorf("no match method for %s", name))
+
+       return result
+}
+
+func newInfoInvoker(url *common.URL, info *ServiceInfo, svc common.RPCService) 
protocol.Invoker {
+       invoker := &infoInvoker{
+               base: protocol.NewBaseInvoker(url),
+               info: info,
+               svc:  svc,
+       }
+       invoker.init()
+       return invoker
+}
+
 // Register assemble invoker chains like ProviderConfig.Load, init a service 
per call
-func (s *Server) Register(handler interface{}, info *ServiceInfo, opts 
...ServerOption) error {
-       for _, opt := range opts {
-               opt(s.cfg)
+func (s *Server) Register(handler interface{}, info *ServiceInfo, opts 
...ServiceOption) error {
+       if s.cfg == nil {
+               return errors.New("Server has not been initialized, please use 
NewServer() to create Server")
+       }
+       var svcOpts []ServiceOption
+       appCfg := s.cfg.Application
+       proCfg := s.cfg.Provider
+       prosCfg := s.cfg.Protocols
+       regsCfg := s.cfg.Registries
+       // todo(DMwangnima): record the registered service
+       newSvcOpts := defaultServiceOptions()
+       if appCfg != nil {
+               svcOpts = append(svcOpts,
+                       SetApplication(s.cfg.Application),
+               )
+       }
+       if proCfg != nil {
+               svcOpts = append(svcOpts,
+                       SetProvider(proCfg),
+               )
        }
+       if prosCfg != nil {
+               svcOpts = append(svcOpts,
+                       SetProtocols(prosCfg),
+               )
+       }
+       if regsCfg != nil {
+               svcOpts = append(svcOpts,
+                       SetRegistries(regsCfg),
+               )
+       }
+
+       // options passed by users have higher priority
+       svcOpts = append(svcOpts, opts...)
+       if err := newSvcOpts.init(svcOpts...); err != nil {
+               return err
+       }
+       newSvcOpts.Implement(handler)
+       if err := newSvcOpts.ExportWithInfo(info); err != nil {
+               return err
+       }
+
+       return nil
+}
 
-       // ProviderConfig.Load
-       // url
+func (s *Server) Serve() error {
+       metadata.ExportMetadataService()
+       registry_exposed.RegisterServiceInstance(s.cfg.Application.Name, 
s.cfg.Application.Tag, s.cfg.Application.MetadataType)
+       select {}
        return nil
 }
 


Reply via email to