+ * If {@link DubboTransported @DubboTransported} annotated classes, the invocation of all methods of
+ * {@link FeignClient @FeignClient} annotated classes.
+ *
+ *
+ * If {@link DubboTransported @DubboTransported} annotated methods of {@link FeignClient @FeignClient} annotated classes.
+ *
+ *
+ *
{@link LoadBalanced @LoadBalanced} {@link RestTemplate} annotated field, method and parameters
+ *
+ *
+ *
+ * @see FeignClient
+ * @see LoadBalanced
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
+@Documented
+public @interface DubboTransported {
+
+ /**
+ * The protocol of Dubbo transport whose value could be used the placeholder "dubbo.transport.protocol"
+ *
+ * @return the default protocol is "dubbo"
+ */
+ String protocol() default "${dubbo.transport.protocol:dubbo}";
+
+ /**
+ * The cluster of Dubbo transport whose value could be used the placeholder "dubbo.transport.cluster"
+ *
+ * @return the default cluster is "failover"
+ */
+ String cluster() default "${dubbo.transport.cluster:failover}";
+
+ /**
+ * Whether to reconnect if connection is lost, if not specify, reconnect is enabled by default, and the interval
+ * for retry connecting is 2000 ms
+ *
+ * @see Constants#DEFAULT_RECONNECT_PERIOD
+ * @see Reference#reconnect()
+ */
+ String reconnect() default "${dubbo.transport.reconnect:2000}";
+
+ /**
+ * Maximum connections service provider can accept, default value is 0 - connection is shared
+ *
+ * @see Reference#connections()
+ */
+ int connections() default 0;
+
+ /**
+ * Service invocation retry times
+ *
+ * @see Constants#DEFAULT_RETRIES
+ * @see Reference#retries()
+ */
+ int retries() default DEFAULT_RETRIES;
+
+ /**
+ * Load balance strategy, legal values include: random, roundrobin, leastactive
+ *
+ * @see Constants#DEFAULT_LOADBALANCE
+ * @see Reference#loadbalance()
+ */
+ String loadbalance() default "${dubbo.transport.loadbalance:}";
+
+ /**
+ * Maximum active requests allowed, default value is 0
+ *
+ * @see Reference#actives()
+ */
+ int actives() default 0;
+
+ /**
+ * Timeout value for service invocation, default value is 0
+ *
+ * @see Reference#timeout()
+ */
+ int timeout() default 0;
+
+ /**
+ * Specify cache implementation for service invocation, legal values include: lru, threadlocal, jcache
+ *
+ * @see Reference#cache()
+ */
+ String cache() default "${dubbo.transport.cache:}";
+
+ /**
+ * Filters for service invocation
+ *
+ * @see Filter
+ * @see Reference#filter()
+ */
+ String[] filter() default {};
+
+ /**
+ * Listeners for service exporting and unexporting
+ *
+ * @see ExporterListener
+ * @see Reference#listener()
+ */
+ String[] listener() default {};
+
+ /**
+ * Customized parameter key-value pair, for example: {key1, value1, key2, value2}
+ *
+ * @see Reference#parameters()
+ */
+ String[] parameters() default {};
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java
new file mode 100644
index 00000000..5447c2b2
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboLoadBalancedRestTemplateAutoConfiguration.java
@@ -0,0 +1,176 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.autoconfigure;
+
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.SmartInitializingSingleton;
+import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.context.event.ApplicationStartedEvent;
+import com.alibaba.cloud.dubbo.annotation.DubboTransported;
+import com.alibaba.cloud.dubbo.client.loadbalancer.DubboMetadataInitializerInterceptor;
+import com.alibaba.cloud.dubbo.client.loadbalancer.DubboTransporterInterceptor;
+import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import com.alibaba.cloud.dubbo.metadata.resolver.DubboTransportedAttributesResolver;
+import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory;
+import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory;
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
+import org.springframework.cloud.client.loadbalancer.RestTemplateCustomizer;
+import org.springframework.cloud.client.loadbalancer.RetryLoadBalancerInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.env.Environment;
+import org.springframework.core.type.MethodMetadata;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Dubbo Auto-{@link Configuration} for {@link LoadBalanced @LoadBalanced} {@link RestTemplate}
+ *
+ * @author Mercy
+ */
+@Configuration
+@ConditionalOnClass(name = {"org.springframework.web.client.RestTemplate"})
+@AutoConfigureAfter(name = {"org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration"})
+public class DubboLoadBalancedRestTemplateAutoConfiguration implements BeanClassLoaderAware, SmartInitializingSingleton {
+
+ private static final Class DUBBO_TRANSPORTED_CLASS = DubboTransported.class;
+
+ private static final String DUBBO_TRANSPORTED_CLASS_NAME = DUBBO_TRANSPORTED_CLASS.getName();
+
+ @Autowired
+ private DubboServiceMetadataRepository repository;
+
+ @Autowired(required = false)
+ private LoadBalancerInterceptor loadBalancerInterceptor;
+
+ @Autowired(required = false)
+ private RetryLoadBalancerInterceptor retryLoadBalancerInterceptor;
+
+ @Autowired
+ private ConfigurableListableBeanFactory beanFactory;
+
+ @Autowired
+ private DubboGenericServiceFactory serviceFactory;
+
+ @Autowired
+ private DubboGenericServiceExecutionContextFactory contextFactory;
+
+ @Autowired
+ private Environment environment;
+
+ @LoadBalanced
+ @Autowired(required = false)
+ private Map restTemplates = Collections.emptyMap();
+
+ private ClassLoader classLoader;
+
+ /**
+ * The {@link ClientHttpRequestInterceptor} bean that may be {@link LoadBalancerInterceptor} or {@link RetryLoadBalancerInterceptor}
+ */
+ private ClientHttpRequestInterceptor loadBalancerInterceptorBean;
+
+ @Override
+ public void afterSingletonsInstantiated() {
+ loadBalancerInterceptorBean = retryLoadBalancerInterceptor != null ?
+ retryLoadBalancerInterceptor :
+ loadBalancerInterceptor;
+ }
+
+ /**
+ * Adapt the {@link RestTemplate} beans that are annotated {@link LoadBalanced @LoadBalanced} and
+ * {@link LoadBalanced @LoadBalanced} when Spring Boot application started
+ * (after the callback of {@link SmartInitializingSingleton} beans or
+ * {@link RestTemplateCustomizer#customize(RestTemplate) customization})
+ */
+ @EventListener(ApplicationStartedEvent.class)
+ public void adaptRestTemplates() {
+
+ DubboTransportedAttributesResolver attributesResolver = new DubboTransportedAttributesResolver(environment);
+
+ for (Map.Entry entry : restTemplates.entrySet()) {
+ String beanName = entry.getKey();
+ Map dubboTranslatedAttributes = getDubboTranslatedAttributes(beanName, attributesResolver);
+ if (!CollectionUtils.isEmpty(dubboTranslatedAttributes)) {
+ adaptRestTemplate(entry.getValue(), dubboTranslatedAttributes);
+ }
+ }
+ }
+
+ /**
+ * Gets the annotation attributes {@link RestTemplate} bean being annotated
+ * {@link DubboTransported @DubboTransported}
+ *
+ * @param beanName the bean name of {@link LoadBalanced @LoadBalanced} {@link RestTemplate}
+ * @param attributesResolver {@link DubboTransportedAttributesResolver}
+ * @return non-null {@link Map}
+ */
+ private Map getDubboTranslatedAttributes(String beanName,
+ DubboTransportedAttributesResolver attributesResolver) {
+ Map attributes = Collections.emptyMap();
+ BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
+ if (beanDefinition instanceof AnnotatedBeanDefinition) {
+ AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition) beanDefinition;
+ MethodMetadata factoryMethodMetadata = annotatedBeanDefinition.getFactoryMethodMetadata();
+ attributes = factoryMethodMetadata != null ?
+ factoryMethodMetadata.getAnnotationAttributes(DUBBO_TRANSPORTED_CLASS_NAME) : Collections.emptyMap();
+ }
+ return attributesResolver.resolve(attributes);
+ }
+
+
+ /**
+ * Adapt the instance of {@link DubboTransporterInterceptor} to the {@link LoadBalancerInterceptor} Bean.
+ *
+ * @param restTemplate {@link LoadBalanced @LoadBalanced} {@link RestTemplate} Bean
+ * @param dubboTranslatedAttributes the annotation dubboTranslatedAttributes {@link RestTemplate} bean being annotated
+ * {@link DubboTransported @DubboTransported}
+ */
+ private void adaptRestTemplate(RestTemplate restTemplate, Map dubboTranslatedAttributes) {
+
+ List interceptors = new ArrayList<>(restTemplate.getInterceptors());
+
+ int index = loadBalancerInterceptorBean == null ? -1 : interceptors.indexOf(loadBalancerInterceptorBean);
+
+ index = index < 0 ? 0 : index;
+
+ // Add ClientHttpRequestInterceptor instances before loadBalancerInterceptor
+ interceptors.add(index++, new DubboMetadataInitializerInterceptor(repository));
+
+ interceptors.add(index++, new DubboTransporterInterceptor(repository, restTemplate.getMessageConverters(),
+ classLoader, dubboTranslatedAttributes, serviceFactory, contextFactory));
+
+ restTemplate.setInterceptors(interceptors);
+ }
+
+ @Override
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java
new file mode 100644
index 00000000..57a58176
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboMetadataAutoConfiguration.java
@@ -0,0 +1,109 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.autoconfigure;
+
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.spring.ServiceBean;
+import org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent;
+
+import feign.Contract;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.event.ApplicationFailedEvent;
+import com.alibaba.cloud.dubbo.metadata.DubboProtocolConfigSupplier;
+import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import com.alibaba.cloud.dubbo.metadata.resolver.DubboServiceBeanMetadataResolver;
+import com.alibaba.cloud.dubbo.metadata.resolver.MetadataResolver;
+import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory;
+import com.alibaba.cloud.dubbo.service.DubboMetadataServiceExporter;
+import com.alibaba.cloud.dubbo.service.DubboMetadataServiceProxy;
+import com.alibaba.cloud.dubbo.service.IntrospectiveDubboMetadataService;
+import com.alibaba.cloud.dubbo.util.JSONUtils;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.context.event.EventListener;
+
+import java.util.Collection;
+import java.util.function.Supplier;
+
+/**
+ * Spring Boot Auto-Configuration class for Dubbo Metadata
+ *
+ * @author Mercy
+ */
+@Configuration
+@Import({DubboServiceMetadataRepository.class,
+ IntrospectiveDubboMetadataService.class,
+ DubboMetadataServiceExporter.class,
+ JSONUtils.class})
+public class DubboMetadataAutoConfiguration {
+
+ @Autowired
+ private ObjectProvider dubboServiceMetadataRepository;
+
+ @Autowired
+ private MetadataResolver metadataResolver;
+
+ @Autowired
+ private DubboMetadataServiceExporter dubboMetadataConfigServiceExporter;
+
+ @Bean
+ @ConditionalOnMissingBean
+ public MetadataResolver metadataJsonResolver(ObjectProvider contract) {
+ return new DubboServiceBeanMetadataResolver(contract);
+ }
+
+ @Bean
+ public Supplier dubboProtocolConfigSupplier(ObjectProvider> protocols) {
+ return new DubboProtocolConfigSupplier(protocols);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public DubboMetadataServiceProxy dubboMetadataConfigServiceProxy(DubboGenericServiceFactory factory) {
+ return new DubboMetadataServiceProxy(factory);
+ }
+
+ // Event-Handling
+
+ @EventListener(ServiceBeanExportedEvent.class)
+ public void onServiceBeanExported(ServiceBeanExportedEvent event) {
+ ServiceBean serviceBean = event.getServiceBean();
+ publishServiceRestMetadata(serviceBean);
+ }
+
+ @EventListener(ApplicationFailedEvent.class)
+ public void onApplicationFailed() {
+ unExportDubboMetadataConfigService();
+ }
+
+ @EventListener(ContextClosedEvent.class)
+ public void onContextClosed() {
+ unExportDubboMetadataConfigService();
+ }
+
+ private void publishServiceRestMetadata(ServiceBean serviceBean) {
+ dubboServiceMetadataRepository.getIfAvailable().publishServiceRestMetadata(metadataResolver.resolveServiceRestMetadata(serviceBean));
+ }
+
+ private void unExportDubboMetadataConfigService() {
+ dubboMetadataConfigServiceExporter.unexport();
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java
new file mode 100644
index 00000000..9f956e05
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboOpenFeignAutoConfiguration.java
@@ -0,0 +1,55 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.autoconfigure;
+
+import com.alibaba.cloud.dubbo.openfeign.TargeterBeanPostProcessor;
+import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory;
+import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory;
+
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+
+import static com.alibaba.cloud.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration.TARGETER_CLASS_NAME;
+
+
+/**
+ * Dubbo Feign Auto-{@link Configuration Configuration}
+ *
+ * @author Mercy
+ */
+@ConditionalOnClass(name = {"feign.Feign", TARGETER_CLASS_NAME})
+@AutoConfigureAfter(name = {"org.springframework.cloud.openfeign.FeignAutoConfiguration"})
+@Configuration
+public class DubboOpenFeignAutoConfiguration {
+
+ public static final String TARGETER_CLASS_NAME = "org.springframework.cloud.openfeign.Targeter";
+
+ @Bean
+ public TargeterBeanPostProcessor targeterBeanPostProcessor(Environment environment,
+ DubboServiceMetadataRepository dubboServiceMetadataRepository,
+ DubboGenericServiceFactory dubboGenericServiceFactory,
+ DubboGenericServiceExecutionContextFactory contextFactory) {
+ return new TargeterBeanPostProcessor(environment, dubboServiceMetadataRepository,
+ dubboGenericServiceFactory, contextFactory);
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java
new file mode 100644
index 00000000..00af57ae
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceAutoConfiguration.java
@@ -0,0 +1,75 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.autoconfigure;
+
+import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory;
+import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory;
+import com.alibaba.cloud.dubbo.service.parameter.PathVariableServiceParameterResolver;
+import com.alibaba.cloud.dubbo.service.parameter.RequestBodyServiceParameterResolver;
+import com.alibaba.cloud.dubbo.service.parameter.RequestHeaderServiceParameterResolver;
+import com.alibaba.cloud.dubbo.service.parameter.RequestParamServiceParameterResolver;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import com.alibaba.cloud.dubbo.env.DubboCloudProperties;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.PropertyResolver;
+
+/**
+ * Spring Boot Auto-Configuration class for Dubbo Service
+ *
+ * @author Mercy
+ */
+@Configuration
+@EnableConfigurationProperties(DubboCloudProperties.class)
+public class DubboServiceAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public DubboGenericServiceFactory dubboGenericServiceFactory() {
+ return new DubboGenericServiceFactory();
+ }
+
+ @Configuration
+ @Import(value = {
+ DubboGenericServiceExecutionContextFactory.class,
+ RequestParamServiceParameterResolver.class,
+ RequestBodyServiceParameterResolver.class,
+ RequestHeaderServiceParameterResolver.class,
+ PathVariableServiceParameterResolver.class
+ })
+ static class ParameterResolversConfiguration {
+ }
+
+ /**
+ * Build a primary {@link PropertyResolver} bean to {@link Autowired @Autowired}
+ *
+ * @param environment {@link Environment}
+ * @return alias bean for {@link Environment}
+ */
+ @Bean
+ @Primary
+ public PropertyResolver primaryPropertyResolver(Environment environment) {
+ return environment;
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java
new file mode 100644
index 00000000..d21e841f
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationAutoConfiguration.java
@@ -0,0 +1,189 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.autoconfigure;
+
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.spring.ServiceBean;
+
+import com.ecwid.consul.v1.agent.model.NewService;
+import com.netflix.appinfo.InstanceInfo;
+import org.aspectj.lang.annotation.Aspect;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.aop.support.AopUtils;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.SmartInitializingSingleton;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.AutoConfigureOrder;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import com.alibaba.cloud.dubbo.autoconfigure.condition.MissingSpringCloudRegistryConfigPropertyCondition;
+import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import com.alibaba.cloud.dubbo.registry.DubboServiceRegistrationEventPublishingAspect;
+import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.serviceregistry.Registration;
+import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
+import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration;
+import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaRegistration;
+import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry;
+import org.springframework.context.SmartLifecycle;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.context.event.EventListener;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME;
+import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.EUREKA_AUTO_CONFIGURATION_CLASS_NAME;
+import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.ADDRESS;
+import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL;
+import static org.springframework.util.ObjectUtils.isEmpty;
+
+/**
+ * Dubbo Service Registration Auto-{@link Configuration}
+ *
+ * @author Mercy
+ */
+@Configuration
+@Import({DubboServiceRegistrationEventPublishingAspect.class})
+@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
+@AutoConfigureAfter(name = {
+ EUREKA_AUTO_CONFIGURATION_CLASS_NAME,
+ CONSUL_AUTO_CONFIGURATION_CLASS_NAME,
+ "org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration"
+}, value = {
+ DubboMetadataAutoConfiguration.class
+})
+public class DubboServiceRegistrationAutoConfiguration {
+
+ public static final String EUREKA_AUTO_CONFIGURATION_CLASS_NAME =
+ "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration";
+
+ public static final String CONSUL_AUTO_CONFIGURATION_CLASS_NAME =
+ "org.springframework.cloud.consul.serviceregistry.ConsulAutoServiceRegistrationAutoConfiguration";
+
+ public static final String CONSUL_AUTO_REGISTRATION_CLASS_NAME =
+ "org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration";
+
+ public static final String ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME =
+ "org.springframework.cloud.zookeeper.serviceregistry.ZookeeperAutoServiceRegistrationAutoConfiguration";
+
+ private static final Logger logger = LoggerFactory.getLogger(DubboServiceRegistrationAutoConfiguration.class);
+
+ @Autowired
+ private DubboServiceMetadataRepository dubboServiceMetadataRepository;
+
+ @Bean
+ @Conditional(value = {
+ MissingSpringCloudRegistryConfigPropertyCondition.class
+ })
+ public RegistryConfig defaultSpringCloudRegistryConfig() {
+ return new RegistryConfig(ADDRESS, PROTOCOL);
+ }
+
+ @EventListener(ServiceInstancePreRegisteredEvent.class)
+ public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
+ Registration registration = event.getSource();
+ attachDubboMetadataServiceMetadata(registration);
+ }
+
+ @Configuration
+ @ConditionalOnBean(name = EUREKA_AUTO_CONFIGURATION_CLASS_NAME)
+ @Aspect
+ class EurekaConfiguration implements SmartInitializingSingleton {
+
+ @Autowired
+ private ObjectProvider> serviceBeans;
+
+ @EventListener(ServiceInstancePreRegisteredEvent.class)
+ public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
+ Registration registration = event.getSource();
+ EurekaRegistration eurekaRegistration = EurekaRegistration.class.cast(registration);
+ InstanceInfo instanceInfo = eurekaRegistration.getApplicationInfoManager().getInfo();
+ attachDubboMetadataServiceMetadata(instanceInfo.getMetadata());
+ }
+
+ /**
+ * {@link EurekaServiceRegistry} will register current {@link ServiceInstance service instance} on
+ * {@link EurekaAutoServiceRegistration#start()} execution(in {@link SmartLifecycle#start() start phase}),
+ * thus this method must {@link ServiceBean#export() export} all {@link ServiceBean ServiceBeans} in advance.
+ */
+ @Override
+ public void afterSingletonsInstantiated() {
+ Collection serviceBeans = this.serviceBeans.getIfAvailable();
+ if (!isEmpty(serviceBeans)) {
+ serviceBeans.forEach(ServiceBean::export);
+ }
+ }
+ }
+
+ @Configuration
+ @ConditionalOnBean(name = CONSUL_AUTO_CONFIGURATION_CLASS_NAME)
+ @AutoConfigureOrder
+ class ConsulConfiguration {
+
+ /**
+ * Handle the pre-registered event of {@link ServiceInstance} for Consul
+ *
+ * @param event {@link ServiceInstancePreRegisteredEvent}
+ */
+ @EventListener(ServiceInstancePreRegisteredEvent.class)
+ public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
+ Registration registration = event.getSource();
+ Class> registrationClass = AopUtils.getTargetClass(registration);
+ String registrationClassName = registrationClass.getName();
+ if (CONSUL_AUTO_REGISTRATION_CLASS_NAME.equalsIgnoreCase(registrationClassName)) {
+ ConsulRegistration consulRegistration = (ConsulRegistration) registration;
+ attachURLsIntoMetadata(consulRegistration);
+ }
+ }
+
+ private void attachURLsIntoMetadata(ConsulRegistration consulRegistration) {
+ NewService newService = consulRegistration.getService();
+ Map serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata();
+ if (!isEmpty(serviceMetadata)) {
+ List tags = newService.getTags();
+ for (Map.Entry entry : serviceMetadata.entrySet()) {
+ tags.add(entry.getKey() + "=" + entry.getValue());
+ }
+ }
+ }
+ }
+
+ private void attachDubboMetadataServiceMetadata(Registration registration) {
+ if (registration == null) {
+ return;
+ }
+ synchronized (registration) {
+ Map metadata = registration.getMetadata();
+ attachDubboMetadataServiceMetadata(metadata);
+ }
+ }
+
+ private void attachDubboMetadataServiceMetadata(Map metadata) {
+ Map serviceMetadata = dubboServiceMetadataRepository.getDubboMetadataServiceMetadata();
+ if (!isEmpty(serviceMetadata)) {
+ metadata.putAll(serviceMetadata);
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java
new file mode 100644
index 00000000..6247a520
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/DubboServiceRegistrationNonWebApplicationAutoConfiguration.java
@@ -0,0 +1,168 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.autoconfigure;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.config.spring.ServiceBean;
+
+import com.ecwid.consul.v1.agent.model.NewService;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.beans.factory.SmartInitializingSingleton;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.event.ApplicationStartedEvent;
+import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import com.alibaba.cloud.dubbo.registry.event.ServiceInstancePreRegisteredEvent;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.serviceregistry.Registration;
+import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
+import org.springframework.cloud.consul.serviceregistry.ConsulAutoRegistration;
+import org.springframework.cloud.consul.serviceregistry.ConsulRegistration;
+import org.springframework.cloud.zookeeper.serviceregistry.ServiceInstanceRegistration;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.event.EventListener;
+
+import java.util.List;
+
+import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.CONSUL_AUTO_CONFIGURATION_CLASS_NAME;
+import static com.alibaba.cloud.dubbo.autoconfigure.DubboServiceRegistrationAutoConfiguration.ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME;
+
+/**
+ * Dubbo Service Registration Auto-{@link Configuration} for Non-Web application
+ *
+ * @author Mercy
+ */
+@Configuration
+@ConditionalOnNotWebApplication
+@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
+@AutoConfigureAfter(DubboServiceRegistrationAutoConfiguration.class)
+@Aspect
+public class DubboServiceRegistrationNonWebApplicationAutoConfiguration {
+
+ private static final String REST_PROTOCOL = "rest";
+
+ @Autowired
+ private ServiceRegistry serviceRegistry;
+
+ @Autowired
+ private Registration registration;
+
+ private volatile Integer serverPort = null;
+
+ private volatile boolean registered = false;
+
+ @Autowired
+ private DubboServiceMetadataRepository repository;
+
+ @Around("execution(* org.springframework.cloud.client.serviceregistry.Registration.getPort())")
+ public Object getPort(ProceedingJoinPoint pjp) throws Throwable {
+ return serverPort != null ? serverPort : pjp.proceed();
+ }
+
+ @EventListener(ApplicationStartedEvent.class)
+ public void onApplicationStarted() {
+ setServerPort();
+ register();
+ }
+
+ private void register() {
+ if (registered) {
+ return;
+ }
+ serviceRegistry.register(registration);
+ registered = true;
+ }
+
+ /**
+ * Set web port from {@link ServiceBean#getExportedUrls() exported URLs} if "rest" protocol is present.
+ */
+ private void setServerPort() {
+ if (serverPort == null) {
+ for (List urls : repository.getAllExportedUrls().values()) {
+ urls.stream()
+ .filter(url -> REST_PROTOCOL.equalsIgnoreCase(url.getProtocol()))
+ .findFirst()
+ .ifPresent(url -> {
+ serverPort = url.getPort();
+ });
+
+ // If REST protocol is not present, use any applied port.
+ if (serverPort == null) {
+ urls.stream()
+ .findAny().ifPresent(url -> {
+ serverPort = url.getPort();
+ });
+ }
+ }
+ }
+ }
+
+ @Configuration
+ @ConditionalOnBean(name = ZOOKEEPER_AUTO_CONFIGURATION_CLASS_NAME)
+ class ZookeeperConfiguration implements SmartInitializingSingleton {
+
+ @Autowired
+ private ServiceInstanceRegistration registration;
+
+ @EventListener(ServiceInstancePreRegisteredEvent.class)
+ public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
+ registration.setPort(serverPort);
+ }
+
+ @Override
+ public void afterSingletonsInstantiated() {
+ // invoke getServiceInstance() method to trigger the ServiceInstance building before register
+ registration.getServiceInstance();
+ }
+ }
+
+ @Configuration
+ @ConditionalOnBean(name = CONSUL_AUTO_CONFIGURATION_CLASS_NAME)
+ class ConsulConfiguration {
+
+ /**
+ * Handle the pre-registered event of {@link ServiceInstance} for Consul
+ *
+ * @param event {@link ServiceInstancePreRegisteredEvent}
+ */
+ @EventListener(ServiceInstancePreRegisteredEvent.class)
+ public void onServiceInstancePreRegistered(ServiceInstancePreRegisteredEvent event) {
+ Registration registration = event.getSource();
+ ConsulAutoRegistration consulRegistration = (ConsulAutoRegistration) registration;
+ setPort(consulRegistration);
+ }
+
+ /**
+ * Set port on Non-Web Application
+ *
+ * @param consulRegistration {@link ConsulRegistration}
+ */
+ private void setPort(ConsulAutoRegistration consulRegistration) {
+ int port = consulRegistration.getPort();
+ NewService newService = consulRegistration.getService();
+ if (newService.getPort() == null) {
+ newService.setPort(port);
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java
new file mode 100644
index 00000000..66429440
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/autoconfigure/condition/MissingSpringCloudRegistryConfigPropertyCondition.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.dubbo.autoconfigure.condition;
+
+import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
+import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
+import com.alibaba.cloud.dubbo.registry.SpringCloudRegistry;
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+import org.springframework.util.StringUtils;
+
+import java.util.Map;
+
+import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties;
+import static com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory.PROTOCOL;
+
+/**
+ * Missing {@link SpringCloudRegistry} Property {@link Condition}
+ *
+ * @see SpringCloudRegistry
+ * @see Condition
+ */
+public class MissingSpringCloudRegistryConfigPropertyCondition extends SpringBootCondition {
+
+
+ @Override
+ public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
+ ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment();
+
+ String protocol = environment.getProperty("dubbo.registry.protocol");
+
+ if (PROTOCOL.equals(protocol)) {
+ return ConditionOutcome.noMatch("'spring-cloud' protocol was found from 'dubbo.registry.protocol'");
+ }
+
+ String address = environment.getProperty("dubbo.registry.address");
+
+ if (StringUtils.startsWithIgnoreCase(address, PROTOCOL)) {
+ return ConditionOutcome.noMatch("'spring-cloud' protocol was found from 'dubbo.registry.address'");
+ }
+
+ Map properties = getSubProperties(environment, "dubbo.registries.");
+
+ boolean found = properties.entrySet().stream().anyMatch(entry -> {
+ String key = entry.getKey();
+ String value = String.valueOf(entry.getValue());
+ return (key.endsWith(".address") && value.startsWith(PROTOCOL)) ||
+ (key.endsWith(".protocol") && PROTOCOL.equals(value));
+
+ });
+
+ return found ? ConditionOutcome.noMatch("'spring-cloud' protocol was found in 'dubbo.registries.*'") : ConditionOutcome.match();
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java
new file mode 100644
index 00000000..c1458ed6
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponse.java
@@ -0,0 +1,78 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.client.loadbalancer;
+
+import org.apache.dubbo.rpc.service.GenericException;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.client.ClientHttpResponse;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Dubbo {@link ClientHttpResponse} implementation
+ *
+ * @author Mercy
+ * @see DubboTransporterInterceptor
+ */
+class DubboClientHttpResponse implements ClientHttpResponse {
+
+ private final HttpStatus httpStatus;
+
+ private final String statusText;
+
+ private final HttpHeaders httpHeaders = new HttpHeaders();
+
+ private final DubboHttpOutputMessage httpOutputMessage;
+
+ public DubboClientHttpResponse(DubboHttpOutputMessage httpOutputMessage, GenericException exception) {
+ this.httpStatus = exception != null ? HttpStatus.INTERNAL_SERVER_ERROR : HttpStatus.OK;
+ this.statusText = exception != null ? exception.getExceptionMessage() : httpStatus.getReasonPhrase();
+ this.httpOutputMessage = httpOutputMessage;
+ this.httpHeaders.putAll(httpOutputMessage.getHeaders());
+ }
+
+ @Override
+ public HttpStatus getStatusCode() throws IOException {
+ return httpStatus;
+ }
+
+ @Override
+ public int getRawStatusCode() throws IOException {
+ return httpStatus.value();
+ }
+
+ @Override
+ public String getStatusText() throws IOException {
+ return statusText;
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+ return httpOutputMessage.getBody().getInputStream();
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return httpHeaders;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java
new file mode 100644
index 00000000..c503ac91
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboClientHttpResponseFactory.java
@@ -0,0 +1,63 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.client.loadbalancer;
+
+import org.apache.dubbo.rpc.service.GenericException;
+import com.alibaba.cloud.dubbo.http.converter.HttpMessageConverterHolder;
+import com.alibaba.cloud.dubbo.http.util.HttpMessageConverterResolver;
+import com.alibaba.cloud.dubbo.metadata.RequestMetadata;
+import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata;
+import org.springframework.http.MediaType;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.http.converter.HttpMessageConverter;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Dubbo {@link ClientHttpResponse} Factory
+ *
+ * @author Mercy
+ */
+class DubboClientHttpResponseFactory {
+
+ private final HttpMessageConverterResolver httpMessageConverterResolver;
+
+ public DubboClientHttpResponseFactory(List> messageConverters, ClassLoader classLoader) {
+ this.httpMessageConverterResolver = new HttpMessageConverterResolver(messageConverters, classLoader);
+ }
+
+ public ClientHttpResponse build(Object result, GenericException exception,
+ RequestMetadata requestMetadata, RestMethodMetadata restMethodMetadata) {
+
+ DubboHttpOutputMessage httpOutputMessage = new DubboHttpOutputMessage();
+
+ HttpMessageConverterHolder httpMessageConverterHolder = httpMessageConverterResolver.resolve(requestMetadata, restMethodMetadata);
+
+ if (httpMessageConverterHolder != null) {
+ MediaType mediaType = httpMessageConverterHolder.getMediaType();
+ HttpMessageConverter converter = httpMessageConverterHolder.getConverter();
+ try {
+ converter.write(result, mediaType, httpOutputMessage);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return new DubboClientHttpResponse(httpOutputMessage, exception);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboHttpOutputMessage.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboHttpOutputMessage.java
new file mode 100644
index 00000000..63457902
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboHttpOutputMessage.java
@@ -0,0 +1,45 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.client.loadbalancer;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpOutputMessage;
+import org.springframework.util.FastByteArrayOutputStream;
+
+import java.io.IOException;
+
+/**
+ * Dubbo {@link HttpOutputMessage} implementation
+ *
+ * @author Mercy
+ */
+class DubboHttpOutputMessage implements HttpOutputMessage {
+
+ private final FastByteArrayOutputStream outputStream = new FastByteArrayOutputStream();
+
+ private final HttpHeaders httpHeaders = new HttpHeaders();
+
+ @Override
+ public FastByteArrayOutputStream getBody() throws IOException {
+ return outputStream;
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return httpHeaders;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java
new file mode 100644
index 00000000..7abf5143
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboMetadataInitializerInterceptor.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.dubbo.client.loadbalancer;
+
+import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * Dubbo Metadata {@link ClientHttpRequestInterceptor} Initializing Interceptor executes intercept before
+ * {@link DubboTransporterInterceptor}
+ *
+ * @author Mercy
+ */
+public class DubboMetadataInitializerInterceptor implements ClientHttpRequestInterceptor {
+
+ private final DubboServiceMetadataRepository repository;
+
+ public DubboMetadataInitializerInterceptor(DubboServiceMetadataRepository repository) {
+ this.repository = repository;
+ }
+
+ @Override
+ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
+
+ URI originalUri = request.getURI();
+
+ String serviceName = originalUri.getHost();
+
+ repository.initialize(serviceName);
+
+ // Execute next
+ return execution.execute(request, body);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java
new file mode 100644
index 00000000..bec422ed
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/client/loadbalancer/DubboTransporterInterceptor.java
@@ -0,0 +1,143 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.client.loadbalancer;
+
+import org.apache.dubbo.rpc.service.GenericException;
+import org.apache.dubbo.rpc.service.GenericService;
+
+import com.alibaba.cloud.dubbo.http.MutableHttpServerRequest;
+import com.alibaba.cloud.dubbo.metadata.DubboRestServiceMetadata;
+import com.alibaba.cloud.dubbo.metadata.RequestMetadata;
+import com.alibaba.cloud.dubbo.metadata.RestMethodMetadata;
+import com.alibaba.cloud.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContext;
+import com.alibaba.cloud.dubbo.service.DubboGenericServiceExecutionContextFactory;
+import com.alibaba.cloud.dubbo.service.DubboGenericServiceFactory;
+import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.PathMatcher;
+import org.springframework.web.util.UriComponents;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import static org.springframework.web.util.UriComponentsBuilder.fromUri;
+
+/**
+ * Dubbo Transporter {@link ClientHttpRequestInterceptor} implementation
+ *
+ * @author Mercy
+ * @see LoadBalancerInterceptor
+ */
+public class DubboTransporterInterceptor implements ClientHttpRequestInterceptor {
+
+ private final DubboServiceMetadataRepository repository;
+
+ private final DubboClientHttpResponseFactory clientHttpResponseFactory;
+
+ private final Map dubboTranslatedAttributes;
+
+ private final DubboGenericServiceFactory serviceFactory;
+
+ private final DubboGenericServiceExecutionContextFactory contextFactory;
+
+ private final PathMatcher pathMatcher = new AntPathMatcher();
+
+ public DubboTransporterInterceptor(DubboServiceMetadataRepository dubboServiceMetadataRepository,
+ List> messageConverters,
+ ClassLoader classLoader,
+ Map dubboTranslatedAttributes,
+ DubboGenericServiceFactory serviceFactory,
+ DubboGenericServiceExecutionContextFactory contextFactory) {
+ this.repository = dubboServiceMetadataRepository;
+ this.dubboTranslatedAttributes = dubboTranslatedAttributes;
+ this.clientHttpResponseFactory = new DubboClientHttpResponseFactory(messageConverters, classLoader);
+ this.serviceFactory = serviceFactory;
+ this.contextFactory = contextFactory;
+ }
+
+ @Override
+ public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
+
+ URI originalUri = request.getURI();
+
+ String serviceName = originalUri.getHost();
+
+ RequestMetadata clientMetadata = buildRequestMetadata(request);
+
+ DubboRestServiceMetadata metadata = repository.get(serviceName, clientMetadata);
+
+ if (metadata == null) {
+ // if DubboServiceMetadata is not found, executes next
+ return execution.execute(request, body);
+ }
+
+ RestMethodMetadata dubboRestMethodMetadata = metadata.getRestMethodMetadata();
+
+ GenericService genericService = serviceFactory.create(metadata, dubboTranslatedAttributes);
+
+ MutableHttpServerRequest httpServerRequest = new MutableHttpServerRequest(request, body);
+
+ customizeRequest(httpServerRequest, dubboRestMethodMetadata, clientMetadata);
+
+ DubboGenericServiceExecutionContext context = contextFactory.create(dubboRestMethodMetadata, httpServerRequest);
+
+ Object result = null;
+ GenericException exception = null;
+
+ try {
+ result = genericService.$invoke(context.getMethodName(), context.getParameterTypes(), context.getParameters());
+ } catch (GenericException e) {
+ exception = e;
+ }
+
+ return clientHttpResponseFactory.build(result, exception, clientMetadata, dubboRestMethodMetadata);
+ }
+
+ protected void customizeRequest(MutableHttpServerRequest httpServerRequest,
+ RestMethodMetadata dubboRestMethodMetadata, RequestMetadata clientMetadata) {
+
+ RequestMetadata dubboRequestMetadata = dubboRestMethodMetadata.getRequest();
+ String pathPattern = dubboRequestMetadata.getPath();
+
+ Map pathVariables = pathMatcher.extractUriTemplateVariables(pathPattern, httpServerRequest.getPath());
+
+ if (!CollectionUtils.isEmpty(pathVariables)) {
+ // Put path variables Map into query parameters Map
+ httpServerRequest.params(pathVariables);
+ }
+
+ }
+
+ private RequestMetadata buildRequestMetadata(HttpRequest request) {
+ UriComponents uriComponents = fromUri(request.getURI()).build(true);
+ RequestMetadata requestMetadata = new RequestMetadata();
+ requestMetadata.setPath(uriComponents.getPath());
+ requestMetadata.setMethod(request.getMethod().name());
+ requestMetadata.setParams(uriComponents.getQueryParams());
+ requestMetadata.setHeaders(request.getHeaders());
+ return requestMetadata;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java
new file mode 100644
index 00000000..83dd9831
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java
@@ -0,0 +1,38 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.context;
+
+import com.alibaba.cloud.dubbo.registry.SpringCloudRegistryFactory;
+import org.springframework.context.ApplicationContextInitializer;
+import org.springframework.context.ConfigurableApplicationContext;
+
+/**
+ * The Dubbo services will be registered as the specified Spring cloud applications that will not be considered
+ * normal ones, but only are used to Dubbo's service discovery even if it is based on Spring Cloud Commons abstraction.
+ * However, current application will be registered by other DiscoveryClientAutoConfiguration.
+ *
+ * @author Mercy
+ */
+public class DubboServiceRegistrationApplicationContextInitializer implements
+ ApplicationContextInitializer {
+
+ @Override
+ public void initialize(ConfigurableApplicationContext applicationContext) {
+ // Set ApplicationContext into SpringCloudRegistryFactory before Dubbo Service Register
+ SpringCloudRegistryFactory.setApplicationContext(applicationContext);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboCloudProperties.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboCloudProperties.java
new file mode 100644
index 00000000..dc349e58
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboCloudProperties.java
@@ -0,0 +1,81 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.env;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import static org.springframework.util.StringUtils.commaDelimitedListToStringArray;
+import static org.springframework.util.StringUtils.hasText;
+import static org.springframework.util.StringUtils.trimAllWhitespace;
+
+/**
+ * Dubbo Cloud {@link ConfigurationProperties Properties}
+ *
+ * @author Mercy
+ */
+@ConfigurationProperties(prefix = "dubbo.cloud")
+public class DubboCloudProperties {
+
+ /**
+ * All services of Dubbo
+ */
+ public static final String ALL_DUBBO_SERVICES = "*";
+
+ /**
+ * The subscribed services, the default value is "*". The multiple value will use comma(",") as the separator.
+ *
+ * @see #ALL_DUBBO_SERVICES
+ */
+ private String subscribedServices = ALL_DUBBO_SERVICES;
+
+ public String getSubscribedServices() {
+ return subscribedServices;
+ }
+
+ public void setSubscribedServices(String subscribedServices) {
+ this.subscribedServices = subscribedServices;
+ }
+
+ /**
+ * Get the subscribed services as a {@link Set} with configuration order.
+ *
+ * @return non-null Read-only {@link Set}
+ */
+ public Set subscribedServices() {
+
+ String[] services = commaDelimitedListToStringArray(getSubscribedServices());
+
+ if (services.length < 1) {
+ return Collections.emptySet();
+ }
+
+ Set subscribedServices = new LinkedHashSet<>();
+
+ for (String service : services) {
+ if (hasText(service)) { // filter blank service name
+ // remove all whitespace
+ subscribedServices.add(trimAllWhitespace(service));
+ }
+ }
+
+ return Collections.unmodifiableSet(subscribedServices);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java
new file mode 100644
index 00000000..b7261e74
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/env/DubboNonWebApplicationEnvironmentPostProcessor.java
@@ -0,0 +1,207 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.env;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.WebApplicationType;
+import org.springframework.boot.env.EnvironmentPostProcessor;
+import org.springframework.core.Ordered;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.MapPropertySource;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.core.env.PropertySource;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.apache.dubbo.common.Constants.DEFAULT_PROTOCOL;
+import static org.apache.dubbo.config.spring.util.PropertySourcesUtils.getSubProperties;
+
+/**
+ * Dubbo {@link WebApplicationType#NONE Non-Web Application} {@link EnvironmentPostProcessor}
+ *
+ * @author Mercy
+ */
+public class DubboNonWebApplicationEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
+
+ private static final String DOT = ".";
+
+ /**
+ * The name of default {@link PropertySource} defined in SpringApplication#configurePropertySources method.
+ */
+ private static final String PROPERTY_SOURCE_NAME = "defaultProperties";
+
+ private static final String SERVER_PORT_PROPERTY_NAME = "server.port";
+
+ private static final String PORT_PROPERTY_NAME = "port";
+
+ private static final String PROTOCOL_PROPERTY_NAME_PREFIX = "dubbo.protocol";
+
+ private static final String PROTOCOL_NAME_PROPERTY_NAME_SUFFIX = DOT + "name";
+
+ private static final String PROTOCOL_PORT_PROPERTY_NAME_SUFFIX = DOT + PORT_PROPERTY_NAME;
+
+ private static final String PROTOCOL_PORT_PROPERTY_NAME = PROTOCOL_PROPERTY_NAME_PREFIX + PROTOCOL_PORT_PROPERTY_NAME_SUFFIX;
+
+ private static final String PROTOCOL_NAME_PROPERTY_NAME = PROTOCOL_PROPERTY_NAME_PREFIX + PROTOCOL_NAME_PROPERTY_NAME_SUFFIX;
+
+ private static final String PROTOCOLS_PROPERTY_NAME_PREFIX = "dubbo.protocols";
+
+ private static final String REST_PROTOCOL = "rest";
+
+ private final Logger logger = LoggerFactory.getLogger(DubboNonWebApplicationEnvironmentPostProcessor.class);
+
+ @Override
+ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
+ WebApplicationType webApplicationType = application.getWebApplicationType();
+
+ if (!WebApplicationType.NONE.equals(webApplicationType)) { // Just works in Non-Web Application
+ if (logger.isDebugEnabled()) {
+ logger.debug("Current application is a Web Application, the process will be ignored.");
+ }
+ return;
+ }
+
+ MutablePropertySources propertySources = environment.getPropertySources();
+ Map defaultProperties = createDefaultProperties(environment);
+ if (!CollectionUtils.isEmpty(defaultProperties)) {
+ addOrReplace(propertySources, defaultProperties);
+ }
+ }
+
+ private Map createDefaultProperties(ConfigurableEnvironment environment) {
+ Map defaultProperties = new HashMap();
+ resetServerPort(environment, defaultProperties);
+ return defaultProperties;
+ }
+
+ /**
+ * Reset server port property if it's absent, whose value is configured by "dubbbo.protocol.port"
+ * or "dubbo.protcols.rest.port"
+ *
+ * @param environment
+ * @param defaultProperties
+ */
+ private void resetServerPort(ConfigurableEnvironment environment, Map defaultProperties) {
+
+ String serverPort = environment.getProperty(SERVER_PORT_PROPERTY_NAME, environment.getProperty(PORT_PROPERTY_NAME));
+
+ if (serverPort != null) {
+ return;
+ }
+
+ serverPort = getRestPortFromProtocolProperty(environment);
+
+ if (serverPort == null) {
+ serverPort = getRestPortFromProtocolsProperties(environment);
+ }
+
+ setServerPort(environment, serverPort, defaultProperties);
+ }
+
+ private String getRestPortFromProtocolProperty(ConfigurableEnvironment environment) {
+
+ String protocol = environment.getProperty(PROTOCOL_NAME_PROPERTY_NAME, DEFAULT_PROTOCOL);
+
+ return isRestProtocol(protocol) ?
+ environment.getProperty(PROTOCOL_PORT_PROPERTY_NAME) :
+ null;
+ }
+
+ private String getRestPortFromProtocolsProperties(ConfigurableEnvironment environment) {
+
+ String restPort = null;
+
+ Map subProperties = getSubProperties(environment, PROTOCOLS_PROPERTY_NAME_PREFIX);
+
+ Properties properties = new Properties();
+
+ properties.putAll(subProperties);
+
+ for (String propertyName : properties.stringPropertyNames()) {
+ if (propertyName.endsWith(PROTOCOL_NAME_PROPERTY_NAME_SUFFIX)) { // protocol name property
+ String protocol = properties.getProperty(propertyName);
+ if (isRestProtocol(protocol)) {
+ String beanName = resolveBeanName(propertyName);
+ if (StringUtils.hasText(beanName)) {
+ restPort = properties.getProperty(beanName + PROTOCOL_PORT_PROPERTY_NAME_SUFFIX);
+ break;
+ }
+ }
+ }
+ }
+
+ return restPort;
+ }
+
+ private String resolveBeanName(String propertyName) {
+ int index = propertyName.indexOf(DOT);
+ return index > -1 ? propertyName.substring(0, index) : null;
+ }
+
+ private void setServerPort(ConfigurableEnvironment environment, String serverPort,
+ Map defaultProperties) {
+ if (serverPort == null) {
+ return;
+ }
+
+ defaultProperties.put(SERVER_PORT_PROPERTY_NAME, serverPort);
+
+ }
+
+ /**
+ * Copy from BusEnvironmentPostProcessor#addOrReplace(MutablePropertySources, Map)
+ *
+ * @param propertySources {@link MutablePropertySources}
+ * @param map Default Dubbo Properties
+ */
+ private void addOrReplace(MutablePropertySources propertySources,
+ Map map) {
+ MapPropertySource target = null;
+ if (propertySources.contains(PROPERTY_SOURCE_NAME)) {
+ PropertySource> source = propertySources.get(PROPERTY_SOURCE_NAME);
+ if (source instanceof MapPropertySource) {
+ target = (MapPropertySource) source;
+ for (String key : map.keySet()) {
+ if (!target.containsProperty(key)) {
+ target.getSource().put(key, map.get(key));
+ }
+ }
+ }
+ }
+ if (target == null) {
+ target = new MapPropertySource(PROPERTY_SOURCE_NAME, map);
+ }
+ if (!propertySources.contains(PROPERTY_SOURCE_NAME)) {
+ propertySources.addLast(target);
+ }
+ }
+
+ @Override
+ public int getOrder() { // Keep LOWEST_PRECEDENCE
+ return LOWEST_PRECEDENCE;
+ }
+
+ private static boolean isRestProtocol(String protocol) {
+ return REST_PROTOCOL.equalsIgnoreCase(protocol);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java
new file mode 100644
index 00000000..83d0b1e6
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/ByteArrayHttpInputMessage.java
@@ -0,0 +1,55 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.http;
+
+import org.apache.dubbo.common.io.UnsafeByteArrayInputStream;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpInputMessage;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Byte array {@link HttpInputMessage} implementation
+ *
+ * @author Mercy
+ */
+class ByteArrayHttpInputMessage implements HttpInputMessage {
+
+ private final HttpHeaders httpHeaders;
+
+ private final InputStream inputStream;
+
+ public ByteArrayHttpInputMessage(byte[] body) {
+ this(new HttpHeaders(), body);
+ }
+
+ public ByteArrayHttpInputMessage(HttpHeaders httpHeaders, byte[] body) {
+ this.httpHeaders = httpHeaders;
+ this.inputStream = new UnsafeByteArrayInputStream(body);
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+ return inputStream;
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return httpHeaders;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java
new file mode 100644
index 00000000..228b8340
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/DefaultHttpRequest.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.dubbo.http;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpRequest;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+import static org.springframework.web.util.UriComponentsBuilder.fromPath;
+
+/**
+ * Default {@link HttpRequest} implementation
+ *
+ * @author Mercy
+ */
+public class DefaultHttpRequest implements HttpRequest {
+
+ private final String method;
+
+ private final URI uri;
+
+ private final HttpHeaders headers = new HttpHeaders();
+
+ public DefaultHttpRequest(String method, String path, Map> params,
+ Map> headers) {
+ this.method = method == null ? HttpMethod.GET.name() : method.toUpperCase();
+ this.uri = buildURI(path, params);
+ this.headers.putAll(headers);
+ }
+
+ private URI buildURI(String path, Map> params) {
+ UriComponentsBuilder builder = fromPath(path)
+ .queryParams(new LinkedMultiValueMap<>(params));
+ return builder.build().toUri();
+ }
+
+ @Override
+ public HttpMethod getMethod() {
+ return HttpMethod.resolve(getMethodValue());
+ }
+
+ @Override
+ public String getMethodValue() {
+ return method;
+ }
+
+ @Override
+ public URI getURI() {
+ return uri;
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return headers;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * {@link HttpRequest} Builder
+ */
+ public static class Builder {
+
+ String method;
+
+ String path;
+
+ MultiValueMap params = new LinkedMultiValueMap<>();
+
+ MultiValueMap headers = new LinkedMultiValueMap<>();
+
+ public Builder method(String method) {
+ this.method = method;
+ return this;
+ }
+
+ public Builder path(String path) {
+ this.path = path;
+ return this;
+ }
+
+ public Builder param(String name, String value) {
+ this.params.add(name, value);
+ return this;
+ }
+
+ public Builder header(String name, String value) {
+ this.headers.add(name, value);
+ return this;
+ }
+
+ public Builder params(Map> params) {
+ this.params.putAll(params);
+ return this;
+ }
+
+ public Builder headers(Map> headers) {
+ this.headers.putAll(headers);
+ return this;
+ }
+
+ public HttpRequest build() {
+ return new DefaultHttpRequest(method, path, params, headers);
+ }
+ }
+
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/HttpServerRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/HttpServerRequest.java
new file mode 100644
index 00000000..00bcbf40
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/HttpServerRequest.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.http;
+
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.HttpRequest;
+import org.springframework.util.MultiValueMap;
+
+/**
+ * HTTP Server Request
+ *
+ * @author Mercy
+ */
+public interface HttpServerRequest extends HttpRequest, HttpInputMessage {
+
+ /**
+ * Return a path of current HTTP request
+ *
+ * @return
+ */
+ String getPath();
+
+ /**
+ * Return a map with parsed and decoded query parameter values.
+ */
+ MultiValueMap getQueryParams();
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java
new file mode 100644
index 00000000..602c685a
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/MutableHttpServerRequest.java
@@ -0,0 +1,100 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.http;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpInputMessage;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpRequest;
+import org.springframework.util.MultiValueMap;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Map;
+
+import static com.alibaba.cloud.dubbo.http.util.HttpUtils.getParameters;
+
+/**
+ * Mutable {@link HttpServerRequest} implementation
+ *
+ * @author Mercy
+ */
+public class MutableHttpServerRequest implements HttpServerRequest {
+
+ private final HttpMethod httpMethod;
+
+ private final URI uri;
+
+ private final String path;
+
+ private final MultiValueMap queryParams;
+
+ private final HttpHeaders httpHeaders;
+
+ private final HttpInputMessage httpInputMessage;
+
+ public MutableHttpServerRequest(HttpRequest httpRequest, byte[] body) {
+ this.httpMethod = httpRequest.getMethod();
+ this.uri = httpRequest.getURI();
+ this.path = uri.getPath();
+ this.httpHeaders = httpRequest.getHeaders();
+ this.queryParams = getParameters(httpRequest);
+ this.httpInputMessage = new ByteArrayHttpInputMessage(body);
+ }
+
+ public MutableHttpServerRequest params(Map params) {
+ queryParams.setAll(params);
+ return this;
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+ return httpInputMessage.getBody();
+ }
+
+ @Override
+ public HttpMethod getMethod() {
+ return httpMethod;
+ }
+
+ // Override method since Spring Framework 5.0
+ @Override
+ public String getMethodValue() {
+ return httpMethod.name();
+ }
+
+ @Override
+ public URI getURI() {
+ return uri;
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ return httpHeaders;
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ @Override
+ public MultiValueMap getQueryParams() {
+ return queryParams;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/converter/HttpMessageConverterHolder.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/converter/HttpMessageConverterHolder.java
new file mode 100644
index 00000000..2a242386
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/converter/HttpMessageConverterHolder.java
@@ -0,0 +1,45 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.http.converter;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+
+/**
+ * {@link HttpMessageConverter} Holder with {@link MediaType}.
+ *
+ * @author Mercy
+ */
+public class HttpMessageConverterHolder {
+
+ private final MediaType mediaType;
+
+ private final HttpMessageConverter> converter;
+
+ public HttpMessageConverterHolder(MediaType mediaType, HttpMessageConverter> converter) {
+ this.mediaType = mediaType;
+ this.converter = converter;
+ }
+
+ public MediaType getMediaType() {
+ return mediaType;
+ }
+
+ public HttpMessageConverter> getConverter() {
+ return converter;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractHttpRequestMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractHttpRequestMatcher.java
new file mode 100644
index 00000000..4bc1c281
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractHttpRequestMatcher.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.alibaba.cloud.dubbo.http.matcher;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * Abstract {@link HttpRequestMatcher} implementation
+ *
+ * @author Rossen Stoyanchev
+ * @author Mercy
+ */
+public abstract class AbstractHttpRequestMatcher implements HttpRequestMatcher {
+
+ /**
+ * Return the discrete items a request condition is composed of.
+ *
+ * For example URL patterns, HTTP request methods, param expressions, etc.
+ *
+ * @return a collection of objects, never {@code null}
+ */
+ protected abstract Collection> getContent();
+
+ /**
+ * The notation to use when printing discrete items of content.
+ *
+ * For example {@code " || "} for URL patterns or {@code " && "} for param
+ * expressions.
+ */
+ protected abstract String getToStringInfix();
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+ return getContent().equals(((AbstractHttpRequestMatcher) other).getContent());
+ }
+
+ @Override
+ public int hashCode() {
+ return getContent().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder("[");
+ for (Iterator> iterator = getContent().iterator(); iterator.hasNext();) {
+ Object expression = iterator.next();
+ builder.append(expression.toString());
+ if (iterator.hasNext()) {
+ builder.append(getToStringInfix());
+ }
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpression.java
new file mode 100644
index 00000000..5f47f1bc
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractMediaTypeExpression.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.http.matcher;
+
+import org.springframework.http.MediaType;
+
+/**
+ * The some source code is scratched from org.springframework.web.servlet.mvc.condition.AbstractMediaTypeExpression
+ *
+ * @author Arjen Poutsma
+ * @author Rossen Stoyanchev
+ * @author Mercy
+ */
+public class AbstractMediaTypeExpression implements MediaTypeExpression, Comparable {
+
+ private final MediaType mediaType;
+
+ private final boolean negated;
+
+ AbstractMediaTypeExpression(String expression) {
+ if (expression.startsWith("!")) {
+ this.negated = true;
+ expression = expression.substring(1);
+ } else {
+ this.negated = false;
+ }
+ this.mediaType = MediaType.parseMediaType(expression);
+ }
+
+ AbstractMediaTypeExpression(MediaType mediaType, boolean negated) {
+ this.mediaType = mediaType;
+ this.negated = negated;
+ }
+
+ @Override
+ public MediaType getMediaType() {
+ return this.mediaType;
+ }
+
+ @Override
+ public boolean isNegated() {
+ return this.negated;
+ }
+
+
+ @Override
+ public int compareTo(AbstractMediaTypeExpression other) {
+ return MediaType.SPECIFICITY_COMPARATOR.compare(this.getMediaType(), other.getMediaType());
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+ AbstractMediaTypeExpression otherExpr = (AbstractMediaTypeExpression) other;
+ return (this.mediaType.equals(otherExpr.mediaType) && this.negated == otherExpr.negated);
+ }
+
+ @Override
+ public int hashCode() {
+ return this.mediaType.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (this.negated) {
+ builder.append('!');
+ }
+ builder.append(this.mediaType.toString());
+ return builder.toString();
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpression.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpression.java
new file mode 100644
index 00000000..877a7aa0
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/AbstractNameValueExpression.java
@@ -0,0 +1,146 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.http.matcher;
+
+import org.springframework.http.HttpRequest;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.StringUtils;
+
+import static org.springframework.util.StringUtils.trimWhitespace;
+
+/**
+ * The some source code is scratched from org.springframework.web.servlet.mvc.condition.AbstractNameValueExpression
+ *
+ * @author Rossen Stoyanchev
+ * @author Arjen Poutsma
+ * @author Mercy
+ */
+abstract class AbstractNameValueExpression implements NameValueExpression {
+
+ protected final String name;
+
+ protected final T value;
+
+ protected final boolean negated;
+
+ AbstractNameValueExpression(String expression) {
+ int separator = expression.indexOf('=');
+ if (separator == -1) {
+ this.negated = expression.startsWith("!");
+ this.name = trimWhitespace((this.negated ? expression.substring(1) : expression));
+ this.value = null;
+ } else {
+ this.negated = (separator > 0) && (expression.charAt(separator - 1) == '!');
+ this.name = trimWhitespace((this.negated ? expression.substring(0, separator - 1)
+ : expression.substring(0, separator)));
+ String valueExpression = getValueExpression(expression, separator);
+ this.value = isExcludedValue(valueExpression) ? null : parseValue(valueExpression);
+ }
+ }
+
+ private String getValueExpression(String expression, int separator) {
+ return trimWhitespace(expression.substring(separator + 1));
+ }
+
+ /**
+ * Exclude the pattern value Expression: "{value}", subclass could override this method.
+ *
+ * @param valueExpression
+ * @return
+ */
+ protected boolean isExcludedValue(String valueExpression) {
+ return StringUtils.hasText(valueExpression) &&
+ valueExpression.startsWith("{")
+ && valueExpression.endsWith("}");
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public T getValue() {
+ return this.value;
+ }
+
+ @Override
+ public boolean isNegated() {
+ return this.negated;
+ }
+
+ public final boolean match(HttpRequest request) {
+ boolean isMatch;
+ if (this.value != null) {
+ isMatch = matchValue(request);
+ } else {
+ isMatch = matchName(request);
+ }
+ return (this.negated ? !isMatch : isMatch);
+ }
+
+
+ protected abstract boolean isCaseSensitiveName();
+
+ protected abstract T parseValue(String valueExpression);
+
+ protected abstract boolean matchName(HttpRequest request);
+
+ protected abstract boolean matchValue(HttpRequest request);
+
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (other == null || getClass() != other.getClass()) {
+ return false;
+ }
+ AbstractNameValueExpression> that = (AbstractNameValueExpression>) other;
+ return ((isCaseSensitiveName() ? this.name.equals(that.name) : this.name.equalsIgnoreCase(that.name)) &&
+ ObjectUtils.nullSafeEquals(this.value, that.value) && this.negated == that.negated);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = (isCaseSensitiveName() ? this.name.hashCode() : this.name.toLowerCase().hashCode());
+ result = 31 * result + (this.value != null ? this.value.hashCode() : 0);
+ result = 31 * result + (this.negated ? 1 : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (this.value != null) {
+ builder.append(this.name);
+ if (this.negated) {
+ builder.append('!');
+ }
+ builder.append('=');
+ builder.append(this.value);
+ } else {
+ if (this.negated) {
+ builder.append('!');
+ }
+ builder.append(this.name);
+ }
+ return builder.toString();
+ }
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/CompositeHttpRequestMatcher.java b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/CompositeHttpRequestMatcher.java
new file mode 100644
index 00000000..255a8829
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/com/alibaba/cloud/dubbo/http/matcher/CompositeHttpRequestMatcher.java
@@ -0,0 +1,73 @@
+/*
+ * 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 com.alibaba.cloud.dubbo.http.matcher;
+
+import org.springframework.http.HttpRequest;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Composite {@link HttpRequestMatcher} implementation
+ *
+ * @author Mercy
+ */
+public abstract class CompositeHttpRequestMatcher extends AbstractHttpRequestMatcher {
+
+ private final List matchers = new LinkedList<>();
+
+ public CompositeHttpRequestMatcher(HttpRequestMatcher... matchers) {
+ this.matchers.addAll(Arrays.asList(matchers));
+ }
+
+ public CompositeHttpRequestMatcher and(HttpRequestMatcher matcher) {
+ this.matchers.add(matcher);
+ return this;
+ }
+
+ @Override
+ public boolean match(HttpRequest request) {
+ for (HttpRequestMatcher matcher : matchers) {
+ if (!matcher.match(request)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected List getMatchers() {
+ return this.matchers;
+ }
+
+ @Override
+ protected Collection> getContent() {
+ List