serviceRestMetadata = new LinkedHashSet<>();
+
+ @Autowired
+ private MetadataResolver metadataResolver;
+
+ @Autowired
+ private MetadataConfigService metadataConfigService;
+
+ @EventListener(ServiceBeanExportedEvent.class)
+ public void recordRestMetadata(ServiceBeanExportedEvent event) throws JsonProcessingException {
+ ServiceBean serviceBean = event.getServiceBean();
+ serviceRestMetadata.addAll(metadataResolver.resolveServiceRestMetadata(serviceBean));
+ }
+
+ /**
+ * Pre-handle Spring Cloud application service registered:
+ *
+ * Put restMetadata
with the JSON format into
+ * {@link Registration#getMetadata() service instances' metadata}
+ *
+ *
+ * @param event {@link InstancePreRegisteredEvent} instance
+ */
+ @EventListener(InstancePreRegisteredEvent.class)
+ public void registerRestMetadata(InstancePreRegisteredEvent event) throws Exception {
+ Registration registration = event.getRegistration();
+ metadataConfigService.publishServiceRestMetadata(registration.getServiceId(), serviceRestMetadata);
+ }
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/context/DubboServiceRegistrationApplicationContextInitializer.java
new file mode 100644
index 000000000..f1283e914
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/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 org.springframework.cloud.alibaba.dubbo.context;
+
+import org.springframework.cloud.alibaba.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/org/springframework/cloud/alibaba/dubbo/metadata/MethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodMetadata.java
new file mode 100644
index 000000000..18abf0e96
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodMetadata.java
@@ -0,0 +1,122 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.metadata;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.apache.commons.lang3.ClassUtils;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * {@link Method} Metadata
+ *
+ * @author Mercy
+ */
+public class MethodMetadata {
+
+ private String name;
+
+ private String returnType;
+
+ private List params;
+
+ @JsonIgnore
+ private Method method;
+
+ public MethodMetadata() {
+ this.params = new LinkedList<>();
+ }
+
+ public MethodMetadata(Method method) {
+ this.name = method.getName();
+ this.returnType = ClassUtils.getName(method.getReturnType());
+ this.params = initParameters(method);
+ this.method = method;
+ }
+
+ private List initParameters(Method method) {
+ int parameterCount = method.getParameterCount();
+ if (parameterCount < 1) {
+ return Collections.emptyList();
+ }
+ List params = new ArrayList<>(parameterCount);
+ Parameter[] parameters = method.getParameters();
+ for (int i = 0; i < parameterCount; i++) {
+ Parameter parameter = parameters[i];
+ MethodParameterMetadata param = toMethodParameterMetadata(i, parameter);
+ params.add(param);
+ }
+ return params;
+ }
+
+ private MethodParameterMetadata toMethodParameterMetadata(int index, Parameter parameter) {
+ MethodParameterMetadata metadata = new MethodParameterMetadata();
+ metadata.setIndex(index);
+ metadata.setName(parameter.getName());
+ metadata.setType(parameter.getType().getTypeName());
+ return metadata;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getReturnType() {
+ return returnType;
+ }
+
+ public void setReturnType(String returnType) {
+ this.returnType = returnType;
+ }
+
+ public List getParams() {
+ return params;
+ }
+
+ public void setParams(List params) {
+ this.params = params;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ MethodMetadata that = (MethodMetadata) o;
+ return Objects.equals(name, that.name) &&
+ Objects.equals(returnType, that.returnType) &&
+ Objects.equals(params, that.params);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, returnType, params);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodParameterMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodParameterMetadata.java
new file mode 100644
index 000000000..fbcaad00a
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/MethodParameterMetadata.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 org.springframework.cloud.alibaba.dubbo.metadata;
+
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+/**
+ * {@link Method} Parameter Metadata
+ *
+ * @author Mercy
+ */
+public class MethodParameterMetadata {
+
+ private int index;
+
+ private String name;
+
+ private String type;
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ MethodParameterMetadata that = (MethodParameterMetadata) o;
+ return index == that.index &&
+ Objects.equals(name, that.name) &&
+ Objects.equals(type, that.type);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(index, name, type);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RequestMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RequestMetadata.java
new file mode 100644
index 000000000..ae3d10dce
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RequestMetadata.java
@@ -0,0 +1,97 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.metadata;
+
+import feign.RequestTemplate;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Request Metadata
+ *
+ * @author Mercy
+ */
+public class RequestMetadata {
+
+ private String method;
+
+ private String url;
+
+ private Map> queries;
+
+ private Map> headers;
+
+ public RequestMetadata() {
+ }
+
+ public RequestMetadata(RequestTemplate requestTemplate) {
+ this.method = requestTemplate.method();
+ this.url = requestTemplate.url();
+ this.queries = requestTemplate.queries();
+ this.headers = requestTemplate.headers();
+ }
+
+ public String getMethod() {
+ return method;
+ }
+
+ public void setMethod(String method) {
+ this.method = method;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public Map> getHeaders() {
+ return headers;
+ }
+
+ public void setHeaders(Map> headers) {
+ this.headers = headers;
+ }
+
+ public Map> getQueries() {
+ return queries;
+ }
+
+ public void setQueries(Map> queries) {
+ this.queries = queries;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RequestMetadata that = (RequestMetadata) o;
+ return Objects.equals(method, that.method) &&
+ Objects.equals(url, that.url) &&
+ Objects.equals(queries, that.queries) &&
+ Objects.equals(headers, that.headers);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(method, url, queries, headers);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java
new file mode 100644
index 000000000..5024fefa5
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/RestMethodMetadata.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.metadata;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Method Request Metadata
+ */
+public class RestMethodMetadata {
+
+ private MethodMetadata method;
+
+ private RequestMetadata request;
+
+ private Map> indexToName;
+
+ public MethodMetadata getMethod() {
+ return method;
+ }
+
+ public void setMethod(MethodMetadata method) {
+ this.method = method;
+ }
+
+ public RequestMetadata getRequest() {
+ return request;
+ }
+
+ public void setRequest(RequestMetadata request) {
+ this.request = request;
+ }
+
+ public Map> getIndexToName() {
+ return indexToName;
+ }
+
+ public void setIndexToName(Map> indexToName) {
+ this.indexToName = indexToName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RestMethodMetadata that = (RestMethodMetadata) o;
+ return Objects.equals(method, that.method) &&
+ Objects.equals(request, that.request) &&
+ Objects.equals(indexToName, that.indexToName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(method, request, indexToName);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/ServiceRestMetadata.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/ServiceRestMetadata.java
new file mode 100644
index 000000000..d5ba11f44
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/ServiceRestMetadata.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.metadata;
+
+import java.util.Set;
+
+/**
+ * Service Rest Metadata
+ *
+ * @author Mercy
+ * @see RestMethodMetadata
+ */
+public class ServiceRestMetadata {
+
+ private String name;
+
+ private Set meta;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Set getMeta() {
+ return meta;
+ }
+
+ public void setMeta(Set meta) {
+ this.meta = meta;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ServiceRestMetadata that = (ServiceRestMetadata) o;
+
+ if (name != null ? !name.equals(that.name) : that.name != null) return false;
+ return meta != null ? meta.equals(that.meta) : that.meta == null;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = name != null ? name.hashCode() : 0;
+ result = 31 * result + (meta != null ? meta.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java
new file mode 100644
index 000000000..57a0a1337
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/repository/DubboServiceMetadataRepository.java
@@ -0,0 +1,118 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.metadata.repository;
+
+import com.alibaba.dubbo.config.spring.ReferenceBean;
+import com.alibaba.dubbo.rpc.service.GenericService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.service.MetadataConfigService;
+import org.springframework.stereotype.Repository;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceGroup;
+import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceInterface;
+import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceSegments;
+import static org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry.getServiceVersion;
+
+/**
+ * Dubbo Service Metadata {@link Repository}
+ *
+ * @author Mercy
+ */
+@Repository
+public class DubboServiceMetadataRepository {
+
+ /**
+ * Key is application name
+ * Value is Map
+ */
+ private Map> genericServicesRepository = new HashMap<>();
+
+ private Map> methodMetadataRepository = new HashMap<>();
+
+ @Autowired
+ private MetadataConfigService metadataConfigService;
+
+ @Value("${dubbo.target.protocol:dubbo}")
+ private String targetProtocol;
+
+ @Value("${dubbo.target.cluster:failover}")
+ private String targetCluster;
+
+ public void updateMetadata(String serviceName) {
+
+ Map genericServicesMap = genericServicesRepository.computeIfAbsent(serviceName, k -> new HashMap<>());
+
+ Map methodMetadataMap = methodMetadataRepository.computeIfAbsent(serviceName, k -> new HashMap<>());
+
+ Set serviceRestMetadataSet = metadataConfigService.getServiceRestMetadata(serviceName);
+
+ for (ServiceRestMetadata serviceRestMetadata : serviceRestMetadataSet) {
+
+ ReferenceBean referenceBean = adaptReferenceBean(serviceRestMetadata);
+
+ serviceRestMetadata.getMeta().forEach(restMethodMetadata -> {
+ RequestMetadata requestMetadata = restMethodMetadata.getRequest();
+ genericServicesMap.put(requestMetadata, referenceBean.get());
+ methodMetadataMap.put(requestMetadata, restMethodMetadata.getMethod());
+ });
+ }
+ }
+
+ public GenericService getGenericService(String serviceName, RequestMetadata requestMetadata) {
+ return getGenericServicesMap(serviceName).get(requestMetadata);
+ }
+
+ public MethodMetadata getMethodMetadata(String serviceName, RequestMetadata requestMetadata) {
+ return getMethodMetadataMap(serviceName).get(requestMetadata);
+ }
+
+ private ReferenceBean adaptReferenceBean(ServiceRestMetadata serviceRestMetadata) {
+ String dubboServiceName = serviceRestMetadata.getName();
+ String[] segments = getServiceSegments(dubboServiceName);
+ String interfaceName = getServiceInterface(segments);
+ String version = getServiceVersion(segments);
+ String group = getServiceGroup(segments);
+
+ ReferenceBean referenceBean = new ReferenceBean();
+ referenceBean.setGeneric(true);
+ referenceBean.setInterface(interfaceName);
+ referenceBean.setVersion(version);
+ referenceBean.setGroup(group);
+ referenceBean.setProtocol(targetProtocol);
+ referenceBean.setCluster(targetCluster);
+
+ return referenceBean;
+ }
+
+ private Map getGenericServicesMap(String serviceName) {
+ return genericServicesRepository.getOrDefault(serviceName, Collections.emptyMap());
+ }
+
+ private Map getMethodMetadataMap(String serviceName) {
+ return methodMetadataRepository.getOrDefault(serviceName, Collections.emptyMap());
+ }
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/FeignMetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/FeignMetadataResolver.java
new file mode 100644
index 000000000..e7f80dd4f
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/FeignMetadataResolver.java
@@ -0,0 +1,190 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.metadata.resolver;
+
+import com.alibaba.dubbo.common.URL;
+import com.alibaba.dubbo.config.spring.ServiceBean;
+import feign.Contract;
+import feign.Feign;
+import feign.MethodMetadata;
+import feign.Util;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.SmartInitializingSingleton;
+import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
+import org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistry;
+import org.springframework.util.ClassUtils;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * The metadata resolver for {@link Feign}
+ *
+ * @author Mercy
+ */
+public class FeignMetadataResolver implements BeanClassLoaderAware, SmartInitializingSingleton, MetadataResolver {
+
+ private static final String[] CONTRACT_CLASS_NAMES = {
+ "feign.jaxrs2.JAXRS2Contract",
+ "org.springframework.cloud.openfeign.support.SpringMvcContract",
+ };
+
+ private final String currentApplicationName;
+
+ private final ObjectProvider contract;
+
+ private ClassLoader classLoader;
+
+ /**
+ * Feign Contracts
+ */
+ private Collection contracts;
+
+ public FeignMetadataResolver(String currentApplicationName, ObjectProvider contract) {
+ this.currentApplicationName = currentApplicationName;
+ this.contract = contract;
+ }
+
+ @Override
+ public void afterSingletonsInstantiated() {
+
+ LinkedList contracts = new LinkedList<>();
+
+ // Add injected Contract if available, for example SpringMvcContract Bean under Spring Cloud Open Feign
+ contract.ifAvailable(contracts::add);
+
+ Stream.of(CONTRACT_CLASS_NAMES)
+ .filter(this::isClassPresent) // filter the existed classes
+ .map(this::loadContractClass) // load Contract Class
+ .map(this::createContract) // create instance by the specified class
+ .forEach(contracts::add); // add the Contract instance into contracts
+
+ this.contracts = Collections.unmodifiableCollection(contracts);
+ }
+
+ private Contract createContract(Class> contractClassName) {
+ return (Contract) BeanUtils.instantiateClass(contractClassName);
+ }
+
+ private Class> loadContractClass(String contractClassName) {
+ return ClassUtils.resolveClassName(contractClassName, classLoader);
+ }
+
+ private boolean isClassPresent(String className) {
+ return ClassUtils.isPresent(className, classLoader);
+ }
+
+ @Override
+ public Set resolveServiceRestMetadata(ServiceBean serviceBean) {
+
+ Object bean = serviceBean.getRef();
+
+ Class> beanType = bean.getClass();
+
+ Set serviceRestMetadata = new LinkedHashSet<>();
+
+ Set methodRestMetadata = resolveMethodRestMetadata(beanType);
+
+ List urls = serviceBean.getExportedUrls();
+
+ urls.stream()
+ .map(SpringCloudRegistry::getServiceName)
+ .forEach(serviceName -> {
+ ServiceRestMetadata metadata = new ServiceRestMetadata();
+ metadata.setName(serviceName);
+ metadata.setMeta(methodRestMetadata);
+ serviceRestMetadata.add(metadata);
+ });
+
+ return serviceRestMetadata;
+ }
+
+ @Override
+ public Set resolveMethodRestMetadata(Class> targetType) {
+ List feignContractMethods = selectFeignContractMethods(targetType);
+ return contracts.stream()
+ .map(contract -> contract.parseAndValidatateMetadata(targetType))
+ .flatMap(v -> v.stream())
+ .map(methodMetadata -> resolveMethodRestMetadata(methodMetadata, targetType, feignContractMethods))
+ .collect(Collectors.toSet());
+ }
+
+ /**
+ * Select feign contract methods
+ *
+ * extract some code from {@link Contract.BaseContract#parseAndValidatateMetadata(java.lang.Class)}
+ *
+ * @param targetType
+ * @return non-null
+ */
+ private List selectFeignContractMethods(Class> targetType) {
+ List methods = new LinkedList<>();
+ for (Method method : targetType.getMethods()) {
+ if (method.getDeclaringClass() == Object.class ||
+ (method.getModifiers() & Modifier.STATIC) != 0 ||
+ Util.isDefault(method)) {
+ continue;
+ }
+ methods.add(method);
+ }
+ return methods;
+ }
+
+ protected RestMethodMetadata resolveMethodRestMetadata(MethodMetadata methodMetadata, Class> targetType,
+ List feignContractMethods) {
+ String configKey = methodMetadata.configKey();
+ Method feignContractMethod = getMatchedFeignContractMethod(targetType, feignContractMethods, configKey);
+
+ RestMethodMetadata metadata = new RestMethodMetadata();
+
+ metadata.setRequest(new RequestMetadata(methodMetadata.template()));
+ metadata.setMethod(new org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata(feignContractMethod));
+ metadata.setIndexToName(methodMetadata.indexToName());
+
+ return metadata;
+ }
+
+ private Method getMatchedFeignContractMethod(Class> targetType, List methods, String expectedConfigKey) {
+ Method matchedMethod = null;
+ for (Method method : methods) {
+ String configKey = Feign.configKey(targetType, method);
+ if (expectedConfigKey.equals(configKey)) {
+ matchedMethod = method;
+ break;
+ }
+ }
+ return matchedMethod;
+ }
+
+ @Override
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/MetadataResolver.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/MetadataResolver.java
new file mode 100644
index 000000000..4956e3870
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/resolver/MetadataResolver.java
@@ -0,0 +1,47 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.metadata.resolver;
+
+import com.alibaba.dubbo.config.spring.ServiceBean;
+import org.springframework.cloud.alibaba.dubbo.metadata.RestMethodMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
+
+import java.util.Set;
+
+/**
+ * The REST metadata resolver
+ *
+ * @author Mercy
+ */
+public interface MetadataResolver {
+
+ /**
+ * Resolve the {@link ServiceRestMetadata} {@link Set set} from {@link ServiceBean}
+ *
+ * @param serviceBean {@link ServiceBean}
+ * @return non-null {@link Set}
+ */
+ Set resolveServiceRestMetadata(ServiceBean serviceBean);
+
+ /**
+ * Resolve {@link RestMethodMetadata} {@link Set set} from {@link Class target type}
+ *
+ * @param targetType {@link Class target type}
+ * @return non-null {@link Set}
+ */
+ Set resolveMethodRestMetadata(Class> targetType);
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/MetadataConfigService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/MetadataConfigService.java
new file mode 100644
index 000000000..28b7a373f
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/MetadataConfigService.java
@@ -0,0 +1,33 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.metadata.service;
+
+import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
+
+import java.util.Set;
+
+/**
+ * Config Service for Metadata
+ *
+ * @author Mercy
+ */
+public interface MetadataConfigService {
+
+ void publishServiceRestMetadata(String serviceName, Set serviceRestMetadata);
+
+ Set getServiceRestMetadata(String serviceName);
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/NacosMetadataConfigService.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/NacosMetadataConfigService.java
new file mode 100644
index 000000000..93ce9281c
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/metadata/service/NacosMetadataConfigService.java
@@ -0,0 +1,97 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.metadata.service;
+
+import com.alibaba.nacos.api.config.ConfigService;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.alibaba.dubbo.metadata.ServiceRestMetadata;
+import org.springframework.cloud.alibaba.nacos.NacosConfigProperties;
+
+import javax.annotation.PostConstruct;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import static com.alibaba.nacos.api.common.Constants.DEFAULT_GROUP;
+
+/**
+ * Nacos {@link MetadataConfigService}
+ *
+ * @author Mercy
+ */
+public class NacosMetadataConfigService implements MetadataConfigService {
+
+ private final ObjectMapper objectMapper = new ObjectMapper();
+
+ @Autowired
+ private NacosConfigProperties nacosConfigProperties;
+
+ private ConfigService configService;
+
+ @PostConstruct
+ public void init() {
+ this.configService = nacosConfigProperties.configServiceInstance();
+ this.objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
+ }
+
+ /**
+ * Get the data Id of service rest metadata
+ */
+ private static String getServiceRestMetadataDataId(String serviceName) {
+ return "metadata:rest:" + serviceName + ".json";
+ }
+
+ @Override
+ public void publishServiceRestMetadata(String serviceName, Set serviceRestMetadata) {
+ String dataId = getServiceRestMetadataDataId(serviceName);
+ String json = writeValueAsString(serviceRestMetadata);
+ try {
+ configService.publishConfig(dataId, DEFAULT_GROUP, json);
+ } catch (NacosException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public Set getServiceRestMetadata(String serviceName) {
+ Set metadata = Collections.emptySet();
+ String dataId = getServiceRestMetadataDataId(serviceName);
+ try {
+ String json = configService.getConfig(dataId, DEFAULT_GROUP, 1000 * 3);
+ metadata = objectMapper.readValue(json,
+ TypeFactory.defaultInstance().constructCollectionType(LinkedHashSet.class, ServiceRestMetadata.class));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return metadata;
+ }
+
+ private String writeValueAsString(Object object) {
+ String content = null;
+ try {
+ content = objectMapper.writeValueAsString(object);
+ } catch (JsonProcessingException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return content;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java
new file mode 100644
index 000000000..0c4d74004
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboFeignClientsConfiguration.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.openfeign;
+
+import feign.Contract;
+import feign.Feign;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration;
+import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.cloud.openfeign.FeignClientsConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+
+/**
+ * Dubbo {@link Configuration} for {@link FeignClient FeignClients}
+ *
+ * @author Mercy
+ * @see DubboOpenFeignAutoConfiguration
+ * @see org.springframework.cloud.openfeign.FeignContext#setConfigurations(List)
+ * @see FeignClientsConfiguration
+ */
+@Configuration
+public class DubboFeignClientsConfiguration {
+
+ @Autowired
+ private Contract contract;
+
+ @Autowired
+ private DubboServiceMetadataRepository dubboServiceRepository;
+
+ @Bean
+ public BeanPostProcessor beanPostProcessor() {
+ return new BeanPostProcessor() {
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ if (bean instanceof Feign.Builder) {
+ Feign.Builder builder = (Feign.Builder) bean;
+ builder.invocationHandlerFactory(new DubboInvocationHandlerFactory(contract, dubboServiceRepository));
+ }
+ return bean;
+ }
+ };
+ }
+
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java
new file mode 100644
index 000000000..622ae340c
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandler.java
@@ -0,0 +1,69 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.openfeign;
+
+import com.alibaba.dubbo.rpc.service.GenericService;
+import org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.MethodParameterMetadata;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * Dubbo {@link GenericService} for {@link InvocationHandler}
+ *
+ * @author Mercy
+ */
+public class DubboInvocationHandler implements InvocationHandler {
+
+ private final Map genericServicesMap;
+
+ private final Map methodMetadata;
+
+ private final InvocationHandler defaultInvocationHandler;
+
+ public DubboInvocationHandler(Map genericServicesMap,
+ Map methodMetadata,
+ InvocationHandler defaultInvocationHandler) {
+ this.genericServicesMap = genericServicesMap;
+ this.methodMetadata = methodMetadata;
+ this.defaultInvocationHandler = defaultInvocationHandler;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+
+ GenericService genericService = genericServicesMap.get(method);
+
+ MethodMetadata methodMetadata = this.methodMetadata.get(method);
+
+ if (genericService == null || methodMetadata == null) {
+ return defaultInvocationHandler.invoke(proxy, method, args);
+ }
+
+ String methodName = methodMetadata.getName();
+
+ String[] parameterTypes = methodMetadata
+ .getParams()
+ .stream()
+ .map(MethodParameterMetadata::getType)
+ .toArray(String[]::new);
+
+ return genericService.$invoke(methodName, parameterTypes, args);
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandlerFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandlerFactory.java
new file mode 100644
index 000000000..4fd67f409
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/openfeign/DubboInvocationHandlerFactory.java
@@ -0,0 +1,101 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.openfeign;
+
+import com.alibaba.dubbo.rpc.service.GenericService;
+import feign.Contract;
+import feign.InvocationHandlerFactory;
+import feign.MethodMetadata;
+import feign.Target;
+import org.springframework.cloud.alibaba.dubbo.metadata.RequestMetadata;
+import org.springframework.cloud.alibaba.dubbo.metadata.repository.DubboServiceMetadataRepository;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static feign.Feign.configKey;
+
+/**
+ * Dubbo {@link InvocationHandlerFactory}
+ *
+ * @author Mercy
+ */
+public class DubboInvocationHandlerFactory implements InvocationHandlerFactory {
+
+ private final static InvocationHandlerFactory DEFAULT_INVOCATION_HANDLER_FACTORY =
+ new InvocationHandlerFactory.Default();
+
+ private final Contract contract;
+
+ private final DubboServiceMetadataRepository dubboServiceRepository;
+
+ public DubboInvocationHandlerFactory(Contract contract, DubboServiceMetadataRepository dubboServiceRepository) {
+ this.contract = contract;
+ this.dubboServiceRepository = dubboServiceRepository;
+ }
+
+ @Override
+ public InvocationHandler create(Target target, Map dispatch) {
+ // The target class annotated @FeignClient
+ Class> targetType = target.type();
+ // Resolve metadata from current @FeignClient type
+ Map methodRequestMetadataMap = resolveMethodRequestMetadataMap(targetType, dispatch.keySet());
+ // @FeignClient specifies the service name
+ String serviceName = target.name();
+ // Update specified metadata
+ dubboServiceRepository.updateMetadata(serviceName);
+
+ Map genericServicesMap = new HashMap<>();
+
+ Map methodMetadataMap = new HashMap<>();
+
+ methodRequestMetadataMap.forEach((method, requestMetadata) -> {
+ GenericService genericService = dubboServiceRepository.getGenericService(serviceName, requestMetadata);
+ org.springframework.cloud.alibaba.dubbo.metadata.MethodMetadata methodMetadata =
+ dubboServiceRepository.getMethodMetadata(serviceName, requestMetadata);
+ genericServicesMap.put(method, genericService);
+ methodMetadataMap.put(method, methodMetadata);
+ });
+
+ InvocationHandler defaultInvocationHandler = DEFAULT_INVOCATION_HANDLER_FACTORY.create(target, dispatch);
+
+ DubboInvocationHandler invocationHandler = new DubboInvocationHandler(genericServicesMap, methodMetadataMap,
+ defaultInvocationHandler);
+
+ return invocationHandler;
+ }
+
+ private Map resolveMethodRequestMetadataMap(Class> targetType, Set methods) {
+ Map requestMetadataMap = resolveRequestMetadataMap(targetType);
+ return methods.stream().collect(Collectors.toMap(method -> method, method ->
+ requestMetadataMap.get(configKey(targetType, method))
+ ));
+ }
+
+ private Map resolveRequestMetadataMap(Class> targetType) {
+ return contract.parseAndValidatateMetadata(targetType)
+ .stream().collect(Collectors.toMap(MethodMetadata::configKey, this::requestMetadata));
+ }
+
+ private RequestMetadata requestMetadata(MethodMetadata methodMetadata) {
+ return new RequestMetadata(methodMetadata.template());
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java
new file mode 100644
index 000000000..9a435ff27
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/DubboRegistration.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.registry;
+
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.serviceregistry.Registration;
+
+import java.net.URI;
+import java.util.Map;
+
+/**
+ * The {@link Registration} of Dubbo uses an external of {@link ServiceInstance} instance as the delegate.
+ *
+ * @author Mercy
+ */
+class DubboRegistration implements Registration {
+
+ private final ServiceInstance delegate;
+
+ public DubboRegistration(ServiceInstance delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public String getServiceId() {
+ return delegate.getServiceId();
+ }
+
+ @Override
+ public String getHost() {
+ return delegate.getHost();
+ }
+
+ @Override
+ public int getPort() {
+ return delegate.getPort();
+ }
+
+ @Override
+ public boolean isSecure() {
+ return delegate.isSecure();
+ }
+
+ @Override
+ public URI getUri() {
+ return delegate.getUri();
+ }
+
+ @Override
+ public Map getMetadata() {
+ return delegate.getMetadata();
+ }
+
+ @Override
+ public String getScheme() {
+ return delegate.getScheme();
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java
new file mode 100644
index 000000000..1904cbd5b
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistry.java
@@ -0,0 +1,443 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.registry;
+
+import com.alibaba.dubbo.common.Constants;
+import com.alibaba.dubbo.common.URL;
+import com.alibaba.dubbo.common.utils.NetUtils;
+import com.alibaba.dubbo.common.utils.UrlUtils;
+import com.alibaba.dubbo.registry.NotifyListener;
+import com.alibaba.dubbo.registry.RegistryFactory;
+import com.alibaba.dubbo.registry.support.FailbackRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.client.DefaultServiceInstance;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.cloud.client.serviceregistry.Registration;
+import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
+import org.springframework.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import static com.alibaba.dubbo.common.Constants.CONFIGURATORS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.CONSUMERS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.PROTOCOL_KEY;
+import static com.alibaba.dubbo.common.Constants.PROVIDERS_CATEGORY;
+import static com.alibaba.dubbo.common.Constants.ROUTERS_CATEGORY;
+
+/**
+ * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
+ *
+ * @author Mercy
+ */
+public class SpringCloudRegistry extends FailbackRegistry {
+
+ /**
+ * All supported categories
+ */
+ private static final String[] ALL_SUPPORTED_CATEGORIES = of(
+ PROVIDERS_CATEGORY,
+ CONSUMERS_CATEGORY,
+ ROUTERS_CATEGORY,
+ CONFIGURATORS_CATEGORY
+ );
+
+ private static final int CATEGORY_INDEX = 0;
+
+ private static final int PROTOCOL_INDEX = CATEGORY_INDEX + 1;
+
+ private static final int SERVICE_INTERFACE_INDEX = PROTOCOL_INDEX + 1;
+
+ private static final int SERVICE_VERSION_INDEX = SERVICE_INTERFACE_INDEX + 1;
+
+ private static final int SERVICE_GROUP_INDEX = SERVICE_VERSION_INDEX + 1;
+
+ private static final String WILDCARD = "*";
+
+ /**
+ * The separator for service name
+ */
+ private static final String SERVICE_NAME_SEPARATOR = ":";
+
+ private final ServiceRegistry serviceRegistry;
+
+ private final DiscoveryClient discoveryClient;
+
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ /**
+ * {@link ScheduledExecutorService} lookup service names(only for Dubbo-OPS)
+ */
+ private volatile ScheduledExecutorService scheduledExecutorService;
+
+ /**
+ * The interval in second of lookup service names(only for Dubbo-OPS)
+ */
+ private static final long LOOKUP_INTERVAL = Long.getLong("dubbo.service.names.lookup.interval", 30);
+
+ public SpringCloudRegistry(URL url, ServiceRegistry serviceRegistry,
+ DiscoveryClient discoveryClient) {
+ super(url);
+ this.serviceRegistry = serviceRegistry;
+ this.discoveryClient = discoveryClient;
+ }
+
+ @Override
+ protected void doRegister(URL url) {
+ final String serviceName = getServiceName(url);
+ final Registration registration = createRegistration(serviceName, url);
+ serviceRegistry.register(registration);
+ }
+
+ @Override
+ protected void doUnregister(URL url) {
+ final String serviceName = getServiceName(url);
+ final Registration registration = createRegistration(serviceName, url);
+ this.serviceRegistry.deregister(registration);
+ }
+
+ @Override
+ protected void doSubscribe(URL url, NotifyListener listener) {
+ List serviceNames = getServiceNames(url, listener);
+ doSubscribe(url, listener, serviceNames);
+ }
+
+ @Override
+ protected void doUnsubscribe(URL url, NotifyListener listener) {
+ if (isAdminProtocol(url)) {
+ shutdownServiceNamesLookup();
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return false;
+ }
+
+ private void shutdownServiceNamesLookup() {
+ if (scheduledExecutorService != null) {
+ scheduledExecutorService.shutdown();
+ }
+ }
+
+ private Registration createRegistration(String serviceName, URL url) {
+ return new DubboRegistration(createServiceInstance(serviceName, url));
+ }
+
+ private ServiceInstance createServiceInstance(String serviceName, URL url) {
+ // Append default category if absent
+ String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
+ URL newURL = url.addParameter(Constants.CATEGORY_KEY, category);
+ newURL = newURL.addParameter(Constants.PROTOCOL_KEY, url.getProtocol());
+ String ip = NetUtils.getLocalHost();
+ int port = newURL.getParameter(Constants.BIND_PORT_KEY, url.getPort());
+ DefaultServiceInstance serviceInstance = new DefaultServiceInstance(serviceName, ip, port, false);
+ serviceInstance.getMetadata().putAll(new LinkedHashMap<>(newURL.getParameters()));
+ return serviceInstance;
+ }
+
+ public static String getServiceName(URL url) {
+ String category = url.getParameter(Constants.CATEGORY_KEY, Constants.DEFAULT_CATEGORY);
+ return getServiceName(url, category);
+ }
+
+ private static String getServiceName(URL url, String category) {
+ StringBuilder serviceNameBuilder = new StringBuilder(category);
+ appendIfPresent(serviceNameBuilder, url.getParameter(PROTOCOL_KEY, url.getProtocol()));
+ appendIfPresent(serviceNameBuilder, url, Constants.INTERFACE_KEY);
+ appendIfPresent(serviceNameBuilder, url, Constants.VERSION_KEY);
+ appendIfPresent(serviceNameBuilder, url, Constants.GROUP_KEY);
+ return serviceNameBuilder.toString();
+ }
+
+ private static void appendIfPresent(StringBuilder target, URL url, String parameterName) {
+ String parameterValue = url.getParameter(parameterName);
+ appendIfPresent(target, parameterValue);
+ }
+
+ private static void appendIfPresent(StringBuilder target, String parameterValue) {
+ if (StringUtils.hasText(parameterValue)) {
+ target.append(SERVICE_NAME_SEPARATOR).append(parameterValue);
+ }
+ }
+
+ private void filterServiceNames(List serviceNames, URL url) {
+
+ final String[] categories = getCategories(url);
+
+ final String targetServiceInterface = url.getServiceInterface();
+
+ final String targetVersion = url.getParameter(Constants.VERSION_KEY);
+
+ final String targetGroup = url.getParameter(Constants.GROUP_KEY);
+
+ filter(serviceNames, new Filter() {
+ @Override
+ public boolean accept(String serviceName) {
+ // split service name to segments
+ // (required) segments[0] = category
+ // (required) segments[1] = serviceInterface
+ // (required) segments[2] = protocol
+ // (required) segments[3] = version
+ // (optional) segments[4] = group
+ String[] segments = getServiceSegments(serviceName);
+ int length = segments.length;
+ if (length < 4) { // must present 4 segments or more
+ return false;
+ }
+
+ String category = getCategory(segments);
+ if (Arrays.binarySearch(categories, category) > -1) { // no match category
+ return false;
+ }
+
+ String protocol = getProtocol(segments);
+ if (StringUtils.hasText(protocol)) {
+ return false;
+ }
+
+ String serviceInterface = getServiceInterface(segments);
+ if (!WILDCARD.equals(targetServiceInterface) &&
+ !Objects.equals(targetServiceInterface, serviceInterface)) { // no match service interface
+ return false;
+ }
+
+ String version = getServiceVersion(segments);
+ if (!WILDCARD.equals(targetVersion) &&
+ !Objects.equals(targetVersion, version)) { // no match service version
+ return false;
+ }
+
+ String group = getServiceGroup(segments);
+ if (group != null && !WILDCARD.equals(targetGroup)
+ && !Objects.equals(targetGroup, group)) { // no match service group
+ return false;
+ }
+
+ return true;
+ }
+ });
+ }
+
+ public static String[] getServiceSegments(String serviceName) {
+ return StringUtils.delimitedListToStringArray(serviceName, SERVICE_NAME_SEPARATOR);
+ }
+
+ public static String getCategory(String[] segments) {
+ return segments[CATEGORY_INDEX];
+ }
+
+ public static String getProtocol(String[] segments) {
+ return segments[PROTOCOL_INDEX];
+ }
+
+ public static String getServiceInterface(String[] segments) {
+ return segments[SERVICE_INTERFACE_INDEX];
+ }
+
+ public static String getServiceVersion(String[] segments) {
+ return segments[SERVICE_VERSION_INDEX];
+ }
+
+ public static String getServiceGroup(String[] segments) {
+ return segments.length > 4 ? segments[SERVICE_GROUP_INDEX] : null;
+ }
+
+ /**
+ * Get the categories from {@link URL}
+ *
+ * @param url {@link URL}
+ * @return non-null array
+ */
+ private String[] getCategories(URL url) {
+ return Constants.ANY_VALUE.equals(url.getServiceInterface()) ?
+ ALL_SUPPORTED_CATEGORIES : of(Constants.DEFAULT_CATEGORY);
+ }
+
+ private List getAllServiceNames() {
+ return discoveryClient.getServices();
+ }
+
+ /**
+ * Get the service names from the specified {@link URL url}
+ *
+ * @param url {@link URL}
+ * @param listener {@link NotifyListener}
+ * @return non-null
+ */
+ private List getServiceNames(URL url, NotifyListener listener) {
+ if (isAdminProtocol(url)) {
+ scheduleServiceNamesLookup(url, listener);
+ return getServiceNamesForOps(url);
+ } else {
+ return doGetServiceNames(url);
+ }
+ }
+
+
+ private boolean isAdminProtocol(URL url) {
+ return Constants.ADMIN_PROTOCOL.equals(url.getProtocol());
+ }
+
+ private void scheduleServiceNamesLookup(final URL url, final NotifyListener listener) {
+ if (scheduledExecutorService == null) {
+ scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
+ scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ List serviceNames = getAllServiceNames();
+ filter(serviceNames, new Filter() {
+ @Override
+ public boolean accept(String serviceName) {
+ boolean accepted = false;
+ for (String category : ALL_SUPPORTED_CATEGORIES) {
+ String prefix = category + SERVICE_NAME_SEPARATOR;
+ if (StringUtils.startsWithIgnoreCase(serviceName, prefix)) {
+ accepted = true;
+ break;
+ }
+ }
+ return accepted;
+ }
+ });
+ doSubscribe(url, listener, serviceNames);
+ }
+ }, LOOKUP_INTERVAL, LOOKUP_INTERVAL, TimeUnit.SECONDS);
+ }
+ }
+
+ private void doSubscribe(final URL url, final NotifyListener listener, final List serviceNames) {
+ for (String serviceName : serviceNames) {
+ List serviceInstances = discoveryClient.getInstances(serviceName);
+ notifySubscriber(url, listener, serviceInstances);
+ // TODO Support Update notification event
+ }
+ }
+
+ private List doGetServiceNames(URL url) {
+ String[] categories = getCategories(url);
+ List serviceNames = new ArrayList(categories.length);
+ for (String category : categories) {
+ final String serviceName = getServiceName(url, category);
+ serviceNames.add(serviceName);
+ }
+ return serviceNames;
+ }
+
+ /**
+ * Notify the Healthy {@link ServiceInstance service instance} to subscriber.
+ *
+ * @param url {@link URL}
+ * @param listener {@link NotifyListener}
+ * @param serviceInstances all {@link ServiceInstance instances}
+ */
+ private void notifySubscriber(URL url, NotifyListener listener, List serviceInstances) {
+ List healthyInstances = new LinkedList(serviceInstances);
+ // Healthy Instances
+ filterHealthyInstances(healthyInstances);
+ List urls = buildURLs(url, healthyInstances);
+ this.notify(url, listener, urls);
+ }
+
+ private void filterHealthyInstances(Collection instances) {
+ filter(instances, new Filter() {
+ @Override
+ public boolean accept(ServiceInstance data) {
+ // TODO check the details of status
+// return serviceRegistry.getStatus(new DubboRegistration(data)) != null;
+ return true;
+ }
+ });
+ }
+
+ private List buildURLs(URL consumerURL, Collection serviceInstances) {
+ if (serviceInstances.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List urls = new LinkedList();
+ for (ServiceInstance serviceInstance : serviceInstances) {
+ URL url = buildURL(serviceInstance);
+ if (UrlUtils.isMatch(consumerURL, url)) {
+ urls.add(url);
+ }
+ }
+ return urls;
+ }
+
+ private URL buildURL(ServiceInstance serviceInstance) {
+ URL url = new URL(serviceInstance.getMetadata().get(Constants.PROTOCOL_KEY),
+ serviceInstance.getHost(),
+ serviceInstance.getPort(),
+ serviceInstance.getMetadata());
+ return url;
+ }
+
+ /**
+ * Get the service names for Dubbo OPS
+ *
+ * @param url {@link URL}
+ * @return non-null
+ */
+ private List getServiceNamesForOps(URL url) {
+ List serviceNames = getAllServiceNames();
+ filterServiceNames(serviceNames, url);
+ return serviceNames;
+ }
+
+ private void filter(Collection collection, Filter filter) {
+ Iterator iterator = collection.iterator();
+ while (iterator.hasNext()) {
+ T data = iterator.next();
+ if (!filter.accept(data)) { // remove if not accept
+ iterator.remove();
+ }
+ }
+ }
+
+ private static T[] of(T... values) {
+ return values;
+ }
+
+ /**
+ * A filter
+ */
+ private interface Filter {
+
+ /**
+ * Tests whether or not the specified data should be accepted.
+ *
+ * @param data The data to be tested
+ * @return true
if and only if data
+ * should be accepted
+ */
+ boolean accept(T data);
+
+ }
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java
new file mode 100644
index 000000000..7402ff974
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/java/org/springframework/cloud/alibaba/dubbo/registry/SpringCloudRegistryFactory.java
@@ -0,0 +1,49 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.registry;
+
+import com.alibaba.dubbo.common.URL;
+import com.alibaba.dubbo.registry.Registry;
+import com.alibaba.dubbo.registry.RegistryFactory;
+
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.cloud.client.serviceregistry.Registration;
+import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * Dubbo {@link RegistryFactory} uses Spring Cloud Service Registration abstraction, whose protocol is "spring-cloud"
+ *
+ * @author Mercy
+ * @see RegistryFactory
+ * @see SpringCloudRegistry
+ */
+public class SpringCloudRegistryFactory implements RegistryFactory {
+
+ private static ApplicationContext applicationContext;
+
+ @Override
+ public Registry getRegistry(URL url) {
+ ServiceRegistry serviceRegistry = applicationContext.getBean(ServiceRegistry.class);
+ DiscoveryClient discoveryClient = applicationContext.getBean(DiscoveryClient.class);
+ return new SpringCloudRegistry(url, serviceRegistry, discoveryClient);
+ }
+
+ public static void setApplicationContext(ApplicationContext applicationContext) {
+ SpringCloudRegistryFactory.applicationContext = applicationContext;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory
new file mode 100644
index 000000000..77ac945aa
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/dubbo/com.alibaba.dubbo.registry.RegistryFactory
@@ -0,0 +1 @@
+spring-cloud=org.springframework.cloud.alibaba.dubbo.registry.SpringCloudRegistryFactory
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..c2627f860
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,7 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboMetadataAutoConfiguration,\
+ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboOpenFeignAutoConfiguration,\
+ org.springframework.cloud.alibaba.dubbo.autoconfigure.DubboRestMetadataRegistrationAutoConfiguration
+
+org.springframework.context.ApplicationContextInitializer=\
+ org.springframework.cloud.alibaba.dubbo.context.DubboServiceRegistrationApplicationContextInitializer
diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java
new file mode 100644
index 000000000..ce32e641e
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/autoconfigure/DubboServiceRegistrationAutoConfigurationTest.java
@@ -0,0 +1,28 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.autoconfigure;
+
+import org.springframework.boot.test.context.SpringBootTest;
+
+/**
+ * {@link DubboServiceRegistrationAutoConfiguration} Test
+ *
+ * @author Mercy
+ */
+@SpringBootTest
+public class DubboServiceRegistrationAutoConfigurationTest {
+}
diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java
new file mode 100644
index 000000000..d7b3d13d2
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/bootstrap/DubboSpringCloudBootstrap.java
@@ -0,0 +1,79 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.bootstrap;
+
+import com.alibaba.dubbo.config.annotation.Reference;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.cloud.alibaba.dubbo.service.EchoService;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Dubbo Spring Cloud Bootstrap
+ */
+@EnableDiscoveryClient
+@EnableAutoConfiguration
+@EnableFeignClients
+@RestController
+public class DubboSpringCloudBootstrap {
+
+ @Reference(version = "1.0.0")
+ private EchoService echoService;
+
+ @Autowired
+ @Lazy
+ private FeignEchoService feignEchoService;
+
+ @GetMapping(value = "/call/echo")
+ public String echo(@RequestParam("message") String message) {
+ return feignEchoService.echo(message);
+ }
+
+ @FeignClient("spring-cloud-alibaba-dubbo")
+ public interface FeignEchoService {
+
+ @GetMapping(value = "/echo")
+ String echo(@RequestParam("message") String message);
+ }
+
+ @Bean
+ public ApplicationRunner applicationRunner() {
+ return arguments -> {
+ // Dubbo Service call
+ System.out.println(echoService.echo("mercyblitz"));
+ // Spring Cloud Open Feign REST Call
+ System.out.println(feignEchoService.echo("mercyblitz"));
+ };
+ }
+
+ public static void main(String[] args) {
+ new SpringApplicationBuilder(DubboSpringCloudBootstrap.class)
+ .run(args);
+ }
+}
+
+
+
diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java
new file mode 100644
index 000000000..e1ad9a9d8
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/DefaultEchoService.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.dubbo.service;
+
+import com.alibaba.dubbo.config.annotation.Service;
+import com.alibaba.dubbo.rpc.RpcContext;
+
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+
+/**
+ * Default {@link EchoService}
+ *
+ * @author Mercy
+ */
+@Service(version = "1.0.0", protocol = {"dubbo", "rest"})
+@RestController
+@Path("/")
+public class DefaultEchoService implements EchoService {
+
+ @Override
+ @GetMapping(value = "/echo"
+// consumes = MediaType.APPLICATION_JSON_VALUE,
+// produces = MediaType.APPLICATION_JSON_UTF8_VALUE
+ )
+ @Path("/echo")
+ @GET
+// @Consumes("application/json")
+// @Produces("application/json;charset=UTF-8")
+ public String echo(@RequestParam @QueryParam("message") String message) {
+ return RpcContext.getContext().getUrl() + " [echo] : " + message;
+ }
+
+ @Override
+ @PostMapping("/plus")
+ @Path("/plus")
+ @POST
+ public String plus(@RequestParam @QueryParam("a") int a, @RequestParam @QueryParam("b") int b) {
+ return null;
+ }
+}
diff --git a/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java
new file mode 100644
index 000000000..10ace8ec1
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/test/java/org/springframework/cloud/alibaba/dubbo/service/EchoService.java
@@ -0,0 +1,30 @@
+/*
+ * 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 org.springframework.cloud.alibaba.dubbo.service;
+
+/**
+ * Echo Service
+ *
+ * @author Mercy
+ */
+public interface EchoService {
+
+ String echo(String message);
+
+ String plus(int a, int b);
+
+}
diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml
new file mode 100644
index 000000000..afdfbfa78
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/test/resources/application.yaml
@@ -0,0 +1,16 @@
+dubbo:
+ scan:
+ base-packages: org.springframework.cloud.alibaba.dubbo.service
+ protocols:
+ dubbo:
+ name: dubbo
+ port: 12345
+ rest:
+ name: rest
+ port: 9090
+ server: netty
+ registry:
+ address: spring-cloud://nacos
+
+server:
+ port: 8080
\ No newline at end of file
diff --git a/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml b/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml
new file mode 100644
index 000000000..c3799608e
--- /dev/null
+++ b/spring-cloud-alibaba-dubbo/src/test/resources/bootstrap.yaml
@@ -0,0 +1,28 @@
+spring:
+ application:
+ name: spring-cloud-alibaba-dubbo
+ cloud:
+ nacos:
+ discovery:
+ server-addr: 127.0.0.1:8848
+ config:
+ server-addr: 127.0.0.1:8848
+
+eureka:
+ client:
+ enabled: false
+
+---
+spring:
+ profiles: eureka
+ cloud:
+ nacos:
+ discovery:
+ enabled: false
+ register-enabled: false
+
+eureka:
+ client:
+ enabled: true
+ service-url:
+ defaultZone: http://127.0.0.1:8761/eureka/
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/env-extension/src/main/java/org/springframework/alicloud/env/extension/ImportExtraConfig.java b/spring-cloud-alibaba-examples/env-extension/src/main/java/org/springframework/alicloud/env/extension/ImportExtraConfig.java
index cfea09fa1..1585c4a97 100644
--- a/spring-cloud-alibaba-examples/env-extension/src/main/java/org/springframework/alicloud/env/extension/ImportExtraConfig.java
+++ b/spring-cloud-alibaba-examples/env-extension/src/main/java/org/springframework/alicloud/env/extension/ImportExtraConfig.java
@@ -1,7 +1,11 @@
package org.springframework.alicloud.env.extension;
-import java.lang.annotation.*;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/account-service/pom.xml
new file mode 100644
index 000000000..219187bcf
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/pom.xml
@@ -0,0 +1,63 @@
+
+
+
+ spring-cloud-alibaba-examples
+ org.springframework.cloud
+ 0.2.2.BUILD-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+ account-service
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-fescar
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountApplication.java b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountApplication.java
new file mode 100644
index 000000000..893d34642
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountApplication.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author xiaojing
+ */
+@SpringBootApplication
+public class AccountApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AccountApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountController.java b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountController.java
new file mode 100644
index 000000000..3738fb87e
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountController.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import java.util.Random;
+
+import com.alibaba.fescar.core.context.RootContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xiaojing
+ */
+@RestController
+public class AccountController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AccountController.class);
+
+ private static final String SUCCESS = "SUCCESS";
+ private static final String FAIL = "FAIL";
+
+ private final JdbcTemplate jdbcTemplate;
+ private Random random;
+
+ public AccountController(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ this.random = new Random();
+ }
+
+ @RequestMapping(value = "/account", method = RequestMethod.POST, produces = "application/json")
+ public String account(String userId, int money) {
+ LOGGER.info("Account Service ... xid: " + RootContext.getXID());
+
+ if (random.nextBoolean()) {
+ throw new RuntimeException("this is a mock Exception");
+ }
+
+ int result = jdbcTemplate.update(
+ "update account_tbl set money = money - ? where user_id = ?",
+ new Object[] { money, userId });
+ LOGGER.info("Account Service End ... ");
+ if (result == 1) {
+ return SUCCESS;
+ }
+ return FAIL;
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
new file mode 100644
index 000000000..62e11cd69
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import java.sql.SQLException;
+import java.util.Random;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.fescar.rm.datasource.DataSourceProxy;
+
+/**
+ * @author xiaojing
+ */
+@Configuration
+public class DatabaseConfiguration {
+
+ private final ApplicationContext applicationContext;
+
+ public DatabaseConfiguration(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public DruidDataSource storageDataSource() throws SQLException {
+
+ Environment environment = applicationContext.getEnvironment();
+
+ String ip = environment.getProperty("mysql.server.ip");
+ String port = environment.getProperty("mysql.server.port");
+ String dbName = environment.getProperty("mysql.db.name");
+
+ String userName = environment.getProperty("mysql.user.name");
+ String password = environment.getProperty("mysql.user.password");
+
+ DruidDataSource druidDataSource = new DruidDataSource();
+ druidDataSource.setUrl("jdbc:mysql://" + ip + ":" + port + "/" + dbName);
+ druidDataSource.setUsername(userName);
+ druidDataSource.setPassword(password);
+ druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
+ druidDataSource.setInitialSize(0);
+ druidDataSource.setMaxActive(180);
+ druidDataSource.setMaxWait(60000);
+ druidDataSource.setMinIdle(0);
+ druidDataSource.setValidationQuery("Select 'x' from DUAL");
+ druidDataSource.setTestOnBorrow(false);
+ druidDataSource.setTestOnReturn(false);
+ druidDataSource.setTestWhileIdle(true);
+ druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
+ druidDataSource.setMinEvictableIdleTimeMillis(25200000);
+ druidDataSource.setRemoveAbandoned(true);
+ druidDataSource.setRemoveAbandonedTimeout(1800);
+ druidDataSource.setLogAbandoned(true);
+ druidDataSource.setFilters("mergeStat");
+ return druidDataSource;
+ }
+
+ @Bean
+ public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) {
+ return new DataSourceProxy(druidDataSource);
+ }
+
+ @Bean
+ public JdbcTemplate jdbcTemplate(DataSourceProxy dataSourceProxy) {
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceProxy);
+
+ jdbcTemplate.update("delete from account_tbl where user_id = 'U100001'");
+ jdbcTemplate.update(
+ "insert into account_tbl(user_id, money) values ('U100001', 10000)");
+
+ return jdbcTemplate;
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.conf
new file mode 100644
index 000000000..b264dd9da
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.conf
@@ -0,0 +1,30 @@
+transport {
+ # tcp udt unix-domain-socket
+ type = "TCP"
+ #NIO NATIVE
+ server = "NIO"
+ #thread factory for netty
+ thread-factory {
+ boss-thread-prefix = "NettyBoss"
+ worker-thread-prefix = "NettyServerNIOWorker"
+ server-executor-thread-prefix = "NettyServerBizHandler"
+ share-boss-worker = false
+ client-selector-thread-prefix = "NettyClientSelector"
+ client-selector-thread-size = 1
+ client-worker-thread-prefix = "NettyClientWorkerThread"
+ # netty boss thread size,will not be used for UDT
+ boss-thread-size = 1
+ #auto default pin or 8
+ worker-thread-size = 8
+ }
+}
+service {
+ #vgroup->rgroup
+ vgroup_mapping.account-service-fescar-service-group = "localRgroup"
+ #only support single node
+ localRgroup.grouplist = "127.0.0.1:8091"
+ #degrade current not support
+ enableDegrade = false
+ #disable
+ disable = false
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.properties
new file mode 100644
index 000000000..10f45c59a
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.properties
@@ -0,0 +1,9 @@
+spring.application.name=account-service
+server.port=18084
+
+mysql.server.ip=127.0.0.1
+mysql.server.port=3306
+mysql.db.name=demo
+
+mysql.user.name=xxxxx
+mysql.user.password=xxxxx
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/business-service/pom.xml
new file mode 100644
index 000000000..6d77872a2
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ spring-cloud-alibaba-examples
+ org.springframework.cloud
+ 0.2.2.BUILD-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+ business-service
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-fescar
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-hystrix
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/BusinessApplication.java b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/BusinessApplication.java
new file mode 100644
index 000000000..c0ed45fc2
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/BusinessApplication.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author xiaojing
+ */
+@SpringBootApplication
+@EnableFeignClients
+public class BusinessApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(BusinessApplication.class, args);
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+ @FeignClient(value = "storage", url = "http://127.0.0.1:18082")
+ public interface StorageService {
+
+ @RequestMapping(path = "/storage/{commodityCode}/{count}")
+ String storage(@RequestParam("commodityCode") String commodityCode,
+ @RequestParam("count") int count);
+
+ }
+
+ @FeignClient(value = "order", url = "http://127.0.0.1:18083")
+ public interface OrderService {
+
+ @RequestMapping(path = "/order", method = RequestMethod.POST)
+ String order(@RequestParam("userId") String userId,
+ @RequestParam("commodityCode") String commodityCode,
+ @RequestParam("orderCount") int orderCount);
+
+ }
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/HomeController.java b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/HomeController.java
new file mode 100644
index 000000000..039074ec0
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/HomeController.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import com.alibaba.fescar.spring.annotation.GlobalTransactional;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.alibaba.cloud.examples.BusinessApplication.OrderService;
+import org.springframework.cloud.alibaba.cloud.examples.BusinessApplication.StorageService;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author xiaojing
+ */
+@RestController
+public class HomeController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class);
+
+ private static final String SUCCESS = "SUCCESS";
+ private static final String FAIL = "FAIL";
+ private static final String USER_ID = "U100001";
+ private static final String COMMODITY_CODE = "C00321";
+ private static final int ORDER_COUNT = 2;
+
+ private final RestTemplate restTemplate;
+ private final OrderService orderService;
+ private final StorageService storageService;
+
+ public HomeController(RestTemplate restTemplate, OrderService orderService,
+ StorageService storageService) {
+ this.restTemplate = restTemplate;
+ this.orderService = orderService;
+ this.storageService = storageService;
+ }
+
+ @GlobalTransactional(timeoutMills = 300000, name = "spring-cloud-demo-tx")
+ @RequestMapping(value = "/fescar/rest", method = RequestMethod.GET, produces = "application/json")
+ public String rest() {
+
+ String result = restTemplate.getForObject(
+ "http://127.0.0.1:18082/storage/" + COMMODITY_CODE + "/" + ORDER_COUNT,
+ String.class);
+
+ if (!SUCCESS.equals(result)) {
+ throw new RuntimeException();
+ }
+
+ String url = "http://127.0.0.1:18083/order";
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+
+ MultiValueMap map = new LinkedMultiValueMap();
+ map.add("userId", USER_ID);
+ map.add("commodityCode", COMMODITY_CODE);
+ map.add("orderCount", ORDER_COUNT + "");
+
+ HttpEntity> request = new HttpEntity>(
+ map, headers);
+
+ ResponseEntity response = restTemplate.postForEntity(url, request,
+ String.class);
+
+ result = response.getBody();
+
+ if (!SUCCESS.equals(result)) {
+ throw new RuntimeException();
+ }
+
+ return SUCCESS;
+ }
+
+ @GlobalTransactional(timeoutMills = 300000, name = "spring-cloud-demo-tx")
+ @RequestMapping(value = "/fescar/feign", method = RequestMethod.GET, produces = "application/json")
+ public String feign() {
+
+ String result = storageService.storage(COMMODITY_CODE, ORDER_COUNT);
+
+ if (!SUCCESS.equals(result)) {
+ throw new RuntimeException();
+ }
+
+ result = orderService.order(USER_ID, COMMODITY_CODE, ORDER_COUNT);
+
+ if (!SUCCESS.equals(result)) {
+ throw new RuntimeException();
+ }
+
+ return SUCCESS;
+
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java
new file mode 100644
index 000000000..6594793a3
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import java.io.Serializable;
+
+public class Order implements Serializable {
+ public long id;
+ public String userId;
+ public String commodityCode;
+ public int count;
+ public int money;
+
+ @Override
+ public String toString() {
+ return "Order{" + "id=" + id + ", userId='" + userId + '\'' + ", commodityCode='"
+ + commodityCode + '\'' + ", count=" + count + ", money=" + money + '}';
+ }
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.conf
new file mode 100644
index 000000000..65b695084
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.conf
@@ -0,0 +1,30 @@
+transport {
+ # tcp udt unix-domain-socket
+ type = "TCP"
+ #NIO NATIVE
+ server = "NIO"
+ #thread factory for netty
+ thread-factory {
+ boss-thread-prefix = "NettyBoss"
+ worker-thread-prefix = "NettyServerNIOWorker"
+ server-executor-thread-prefix = "NettyServerBizHandler"
+ share-boss-worker = false
+ client-selector-thread-prefix = "NettyClientSelector"
+ client-selector-thread-size = 1
+ client-worker-thread-prefix = "NettyClientWorkerThread"
+ # netty boss thread size,will not be used for UDT
+ boss-thread-size = 1
+ #auto default pin or 8
+ worker-thread-size = 8
+ }
+}
+service {
+ #vgroup->rgroup
+ vgroup_mapping.business-service-fescar-service-group = "localRgroup"
+ #only support single node
+ localRgroup.grouplist = "127.0.0.1:8091"
+ #degrade current not support
+ enableDegrade = false
+ #disable
+ disable = false
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.properties
new file mode 100644
index 000000000..1832ce6f5
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.properties
@@ -0,0 +1,8 @@
+server.port=18081
+spring.application.name=business-service
+# The following configuration can be omitted.
+
+#feign.hystrix.enabled=true
+#feign.sentinel.enabled=true
+
+logging.level.com.alibaba.fescar=debug
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/order-service/pom.xml
new file mode 100644
index 000000000..7840c5462
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/pom.xml
@@ -0,0 +1,63 @@
+
+
+
+ spring-cloud-alibaba-examples
+ org.springframework.cloud
+ 0.2.2.BUILD-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+ order-service
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-fescar
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
new file mode 100644
index 000000000..8e5c7d87b
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import java.sql.SQLException;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.fescar.rm.datasource.DataSourceProxy;
+
+/**
+ * @author xiaojing
+ */
+@Configuration
+public class DatabaseConfiguration {
+
+ private final ApplicationContext applicationContext;
+
+ public DatabaseConfiguration(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public DruidDataSource storageDataSource() throws SQLException {
+
+ Environment env = applicationContext.getEnvironment();
+
+ String ip = env.getProperty("mysql.server.ip");
+ String port = env.getProperty("mysql.server.port");
+ String dbName = env.getProperty("mysql.db.name");
+
+ String userName = env.getProperty("mysql.user.name");
+ String password = env.getProperty("mysql.user.password");
+
+ DruidDataSource druidDataSource = new DruidDataSource();
+ druidDataSource.setUrl("jdbc:mysql://" + ip + ":" + port + "/" + dbName);
+ druidDataSource.setUsername(userName);
+ druidDataSource.setPassword(password);
+ druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
+ druidDataSource.setInitialSize(0);
+ druidDataSource.setMaxActive(180);
+ druidDataSource.setMaxWait(60000);
+ druidDataSource.setMinIdle(0);
+ druidDataSource.setValidationQuery("Select 'x' from DUAL");
+ druidDataSource.setTestOnBorrow(false);
+ druidDataSource.setTestOnReturn(false);
+ druidDataSource.setTestWhileIdle(true);
+ druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
+ druidDataSource.setMinEvictableIdleTimeMillis(25200000);
+ druidDataSource.setRemoveAbandoned(true);
+ druidDataSource.setRemoveAbandonedTimeout(1800);
+ druidDataSource.setLogAbandoned(true);
+ druidDataSource.setFilters("mergeStat");
+ return druidDataSource;
+ }
+
+ @Bean
+ public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) {
+ return new DataSourceProxy(druidDataSource);
+ }
+
+ @Bean
+ public JdbcTemplate jdbcTemplate(DataSourceProxy dataSourceProxy) {
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceProxy);
+
+ jdbcTemplate.execute("TRUNCATE TABLE order_tbl");
+
+ return jdbcTemplate;
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OderApplication.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OderApplication.java
new file mode 100644
index 000000000..1ab0dab11
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OderApplication.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author xiaojing
+ */
+@SpringBootApplication
+public class OderApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(OderApplication.class, args);
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java
new file mode 100644
index 000000000..6594793a3
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import java.io.Serializable;
+
+public class Order implements Serializable {
+ public long id;
+ public String userId;
+ public String commodityCode;
+ public int count;
+ public int money;
+
+ @Override
+ public String toString() {
+ return "Order{" + "id=" + id + ", userId='" + userId + '\'' + ", commodityCode='"
+ + commodityCode + '\'' + ", count=" + count + ", money=" + money + '}';
+ }
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OrderController.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OrderController.java
new file mode 100644
index 000000000..2e0e0f81c
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OrderController.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Random;
+
+import com.alibaba.fescar.core.context.RootContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.PreparedStatementCreator;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+import org.springframework.jdbc.support.KeyHolder;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author xiaojing
+ */
+@RestController
+public class OrderController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(OrderController.class);
+ private static final String SUCCESS = "SUCCESS";
+ private static final String FAIL = "FAIL";
+ private static final String USER_ID = "U100001";
+ private static final String COMMODITY_CODE = "C00321";
+
+ private final JdbcTemplate jdbcTemplate;
+ private final RestTemplate restTemplate;
+ private Random random;
+
+ public OrderController(JdbcTemplate jdbcTemplate, RestTemplate restTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ this.restTemplate = restTemplate;
+ this.random = new Random();
+ }
+
+ @RequestMapping(value = "/order", method = RequestMethod.POST, produces = "application/json")
+ public String order(String userId, String commodityCode, int orderCount) {
+ LOGGER.info("Order Service Begin ... xid: " + RootContext.getXID());
+
+ int orderMoney = calculate(commodityCode, orderCount);
+
+ invokerAccountService(orderMoney);
+
+ final Order order = new Order();
+ order.userId = userId;
+ order.commodityCode = commodityCode;
+ order.count = orderCount;
+ order.money = orderMoney;
+
+ KeyHolder keyHolder = new GeneratedKeyHolder();
+
+ int result = jdbcTemplate.update(new PreparedStatementCreator() {
+
+ @Override
+ public PreparedStatement createPreparedStatement(Connection con)
+ throws SQLException {
+ PreparedStatement pst = con.prepareStatement(
+ "insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)",
+ PreparedStatement.RETURN_GENERATED_KEYS);
+ pst.setObject(1, order.userId);
+ pst.setObject(2, order.commodityCode);
+ pst.setObject(3, order.count);
+ pst.setObject(4, order.money);
+ return pst;
+ }
+ }, keyHolder);
+
+ order.id = (long) keyHolder.getKey();
+
+ if (random.nextBoolean()) {
+ throw new RuntimeException("this is a mock Exception");
+ }
+
+ LOGGER.info("Order Service End ... Created " + order);
+
+ if (result == 1) {
+ return SUCCESS;
+ }
+ return FAIL;
+ }
+
+ private int calculate(String commodityId, int orderCount) {
+ return 2 * orderCount;
+ }
+
+ private void invokerAccountService(int orderMoney) {
+ String url = "http://127.0.0.1:18084/account";
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+
+ MultiValueMap map = new LinkedMultiValueMap();
+
+ map.add("userId", USER_ID);
+ map.add("money", orderMoney + "");
+
+ HttpEntity> request = new HttpEntity>(
+ map, headers);
+
+ ResponseEntity response = restTemplate.postForEntity(url, request,
+ String.class);
+ }
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.conf
new file mode 100644
index 000000000..c298ca0c2
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.conf
@@ -0,0 +1,30 @@
+transport {
+ # tcp udt unix-domain-socket
+ type = "TCP"
+ #NIO NATIVE
+ server = "NIO"
+ #thread factory for netty
+ thread-factory {
+ boss-thread-prefix = "NettyBoss"
+ worker-thread-prefix = "NettyServerNIOWorker"
+ server-executor-thread-prefix = "NettyServerBizHandler"
+ share-boss-worker = false
+ client-selector-thread-prefix = "NettyClientSelector"
+ client-selector-thread-size = 1
+ client-worker-thread-prefix = "NettyClientWorkerThread"
+ # netty boss thread size,will not be used for UDT
+ boss-thread-size = 1
+ #auto default pin or 8
+ worker-thread-size = 8
+ }
+}
+service {
+ #vgroup->rgroup
+ vgroup_mapping.order-service-fescar-service-group = "localRgroup"
+ #only support single node
+ localRgroup.grouplist = "127.0.0.1:8091"
+ #degrade current not support
+ enableDegrade = false
+ #disable
+ disable = false
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.properties
new file mode 100644
index 000000000..f3e417d8d
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.properties
@@ -0,0 +1,9 @@
+spring.application.name=order-service
+server.port=18083
+
+mysql.server.ip=127.0.0.1
+mysql.server.port=3306
+mysql.db.name=demo
+
+mysql.user.name=xxxxx
+mysql.user.password=xxxxx
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/readme-zh.md b/spring-cloud-alibaba-examples/fescar-example/readme-zh.md
new file mode 100644
index 000000000..e93f6866e
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/readme-zh.md
@@ -0,0 +1,156 @@
+# Fescar Example
+
+## 项目说明
+
+
+本项目演示如何使用 Fescar Starter 完成 Spring Cloud 应用的分布式事务接入。
+
+[Fescar](https://github.com/alibaba/fescar) 是 阿里巴巴 开源的 分布式事务中间件,以 高效 并且对业务 0 侵入 的方式,解决 微服务 场景下面临的分布式事务问题。
+
+
+
+## 准备工作
+
+在运行此示例之前,你需要先完成如下几步准备工作:
+
+1. 配置数据库
+
+1. 创建 UNDO_LOG 表
+
+1. 创建 示例中 业务所需要的数据库表
+
+1. 启动 Fescar Server
+
+
+### 配置数据库
+
+首先,你需要有一个支持 InnoDB 引擎的 MySQL 数据库。
+
+**注意**: 实际上,Fescar 支持不同的应用使用完全不相干的数据库,但是这里为了简单地演示一个原理,所以我们选择了只使用一个数据库。
+
+将 `account-server`、`order-service`、`storage-service` 这三个应用中的 resources 目录下的 `application.properties` 文件中的如下配置修改成你运行环境中的实际配置。
+
+```
+mysql.server.ip=your mysql server ip address
+mysql.server.port=your mysql server listening port
+mysql.db.name=your database name for test
+
+mysql.user.name=your mysql server username
+mysql.user.password=your mysql server password
+
+```
+
+### 创建 UNDO_LOG 表
+
+[Fescar AT 模式]() 需要使用到 UNDO_LOG 表。
+
+``` $sql
+CREATE TABLE `undo_log` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `branch_id` bigint(20) NOT NULL,
+ `xid` varchar(100) NOT NULL,
+ `rollback_info` longblob NOT NULL,
+ `log_status` int(11) NOT NULL,
+ `log_created` datetime NOT NULL,
+ `log_modified` datetime NOT NULL,
+ `ext` varchar(100) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx_unionkey` (`xid`,`branch_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=159 DEFAULT CHARSET=utf8
+```
+
+### 创建 示例中 业务所需要的数据库表
+
+```$sql
+DROP TABLE IF EXISTS `storage_tbl`;
+CREATE TABLE `storage_tbl` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `commodity_code` varchar(255) DEFAULT NULL,
+ `count` int(11) DEFAULT 0,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY (`commodity_code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+DROP TABLE IF EXISTS `order_tbl`;
+CREATE TABLE `order_tbl` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `user_id` varchar(255) DEFAULT NULL,
+ `commodity_code` varchar(255) DEFAULT NULL,
+ `count` int(11) DEFAULT 0,
+ `money` int(11) DEFAULT 0,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+DROP TABLE IF EXISTS `account_tbl`;
+CREATE TABLE `account_tbl` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `user_id` varchar(255) DEFAULT NULL,
+ `money` int(11) DEFAULT 0,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+```
+
+### 启动 Fescar Server
+
+点击这个页面 [https://github.com/alibaba/fescar/releases](https://github.com/alibaba/fescar/releases),下载最新版本的 Fescar Server 端.
+
+
+进入解压之后的 bin 目录,执行如下命令来启动
+
+```$shell
+sh fescar-server.sh $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA
+```
+
+在这个示例中,采用如下命令来启动 Fescar Server
+
+```$shell
+sh fescar-server.sh 8091 ~/fescar/data/
+```
+
+**注意** 如果你修改了端口号,那么记得需要在各个示例工程中的 `application.conf` 文件中,修改 grouplist 的值。
+
+
+## 运行示例
+
+分别运行 `account-server`、`order-service`、`storage-service` 和 `business-service` 这三个应用的 Main 函数,启动示例。
+
+启动示例后,通过 HTTP 的 GET 方法访问如下两个 URL,可以分别验证在 `business-service` 中 通过 RestTemplate 和 FeignClient 调用其他服务的场景。
+
+```$xslt
+http://127.0.0.1:18081/fescar/feign
+
+http://127.0.0.1:18081/fescar/rest
+```
+
+## 如何验证分布式事务成功?
+
+### Xid 信息是否成功传递
+
+在 `account-server`、`order-service` 和 `storage-service` 三个 服务的 Controller 中,第一个执行的逻辑都是输出 RootContext 中的 Xid 信息,如果看到都输出了正确的 Xid 信息,即每次都发生变化,且同一次调用中所有服务的 Xid 都一致。则表明 Fescar 的 Xid 的传递和还原是正常的。
+
+### 数据库中数据是否一致
+
+在本示例中,我们模拟了一个用户购买货物的场景,StorageService 负责扣减库存数量,OrderService 负责保存订单,AccountService 负责扣减用户账户余额。
+
+为了演示样例,我们在 OrderService 和 AccountService 中 使用 Random.nextBoolean() 的方式来随机抛出异常,模拟了在服务调用时随机发生异常的场景。
+
+如果分布式事务生效的话, 那么以下等式应该成立
+
+
+- 用户原始金额(1000) = 用户现存的金额 + 货物单价 (2) * 订单数量 * 每单的货物数量(2)
+
+- 货物的初始数量(100) = 货物的现存数量 + 订单数量 * 每单的货物数量(2)
+
+## 对 Spring Cloud 支持点
+
+- 通过 Spring MVC 提供服务的服务提供者,在收到 header 中含有 Fescar 信息的 HTTP 请求时,可以自动还原 Fescar 上下文。
+
+- 支持服务调用者通过 RestTemplate 调用时,自动传递 Fescar 上下文。
+
+- 支持服务调用者通过 FeignClient 调用时,自动传递 Fescar 上下文。
+
+- 支持 FeignClient 和 Hystrix 同时使用的场景。
+
+- 支持 FeignClient 和 Sentinel 同时使用的场景。
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/storage-service/pom.xml
new file mode 100644
index 000000000..bcdca22c0
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/pom.xml
@@ -0,0 +1,68 @@
+
+
+
+ spring-cloud-alibaba-examples
+ org.springframework.cloud
+ 0.2.2.BUILD-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+ storage-service
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-fescar
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ com.alibaba
+ druid
+ 1.1.10
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
new file mode 100644
index 000000000..2973f21ae
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import java.sql.SQLException;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.fescar.rm.datasource.DataSourceProxy;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * @author xiaojing
+ */
+@Configuration
+public class DatabaseConfiguration {
+
+ private final ApplicationContext applicationContext;
+
+ public DatabaseConfiguration(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public DruidDataSource storageDataSource() throws SQLException {
+
+ Environment environment = applicationContext.getEnvironment();
+
+ String ip = environment.getProperty("mysql.server.ip");
+ String port = environment.getProperty("mysql.server.port");
+ String dbName = environment.getProperty("mysql.db.name");
+
+ String userName = environment.getProperty("mysql.user.name");
+ String password = environment.getProperty("mysql.user.password");
+
+ DruidDataSource druidDataSource = new DruidDataSource();
+ druidDataSource.setUrl("jdbc:mysql://" + ip + ":" + port + "/" + dbName);
+ druidDataSource.setUsername(userName);
+ druidDataSource.setPassword(password);
+ druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
+ druidDataSource.setInitialSize(0);
+ druidDataSource.setMaxActive(180);
+ druidDataSource.setMaxWait(60000);
+ druidDataSource.setMinIdle(0);
+ druidDataSource.setValidationQuery("Select 'x' from DUAL");
+ druidDataSource.setTestOnBorrow(false);
+ druidDataSource.setTestOnReturn(false);
+ druidDataSource.setTestWhileIdle(true);
+ druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
+ druidDataSource.setMinEvictableIdleTimeMillis(25200000);
+ druidDataSource.setRemoveAbandoned(true);
+ druidDataSource.setRemoveAbandonedTimeout(1800);
+ druidDataSource.setLogAbandoned(true);
+ druidDataSource.setFilters("mergeStat");
+ return druidDataSource;
+ }
+
+ @Bean
+ public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) {
+ return new DataSourceProxy(druidDataSource);
+ }
+
+ @Bean
+ public JdbcTemplate jdbcTemplate(DataSourceProxy dataSourceProxy) {
+
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceProxy);
+
+ jdbcTemplate.update("delete from storage_tbl where commodity_code = 'C00321'");
+ jdbcTemplate.update(
+ "insert into storage_tbl(commodity_code, count) values ('C00321', 100)");
+
+ return jdbcTemplate;
+
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageApplication.java b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageApplication.java
new file mode 100644
index 000000000..94bbac7f4
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageApplication.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author xiaojing
+ */
+@SpringBootApplication
+public class StorageApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(StorageApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageController.java b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageController.java
new file mode 100644
index 000000000..fd97ab2c8
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed 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 org.springframework.cloud.alibaba.cloud.examples;
+
+import com.alibaba.fescar.core.context.RootContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xiaojing
+ */
+@RestController
+public class StorageController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(StorageController.class);
+
+ private static final String SUCCESS = "SUCCESS";
+ private static final String FAIL = "FAIL";
+
+ private final JdbcTemplate jdbcTemplate;
+
+ public StorageController(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ @RequestMapping(value = "/storage/{commodityCode}/{count}", method = RequestMethod.GET, produces = "application/json")
+ public String echo(@PathVariable String commodityCode, @PathVariable int count) {
+ LOGGER.info("Storage Service Begin ... xid: " + RootContext.getXID());
+ int result = jdbcTemplate.update(
+ "update storage_tbl set count = count - ? where commodity_code = ?",
+ new Object[] { count, commodityCode });
+ LOGGER.info("Storage Service End ... ");
+ if (result == 1) {
+ return SUCCESS;
+ }
+ return FAIL;
+ }
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.conf
new file mode 100644
index 000000000..4bc5989e1
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.conf
@@ -0,0 +1,30 @@
+transport {
+ # tcp udt unix-domain-socket
+ type = "TCP"
+ #NIO NATIVE
+ server = "NIO"
+ #thread factory for netty
+ thread-factory {
+ boss-thread-prefix = "NettyBoss"
+ worker-thread-prefix = "NettyServerNIOWorker"
+ server-executor-thread-prefix = "NettyServerBizHandler"
+ share-boss-worker = false
+ client-selector-thread-prefix = "NettyClientSelector"
+ client-selector-thread-size = 1
+ client-worker-thread-prefix = "NettyClientWorkerThread"
+ # netty boss thread size,will not be used for UDT
+ boss-thread-size = 1
+ #auto default pin or 8
+ worker-thread-size = 8
+ }
+}
+service {
+ #vgroup->rgroup
+ vgroup_mapping.storage-service-fescar-service-group = "localRgroup"
+ #only support single node
+ localRgroup.grouplist = "127.0.0.1:8091"
+ #degrade current not support
+ enableDegrade = false
+ #disable
+ disable = false
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.properties
new file mode 100644
index 000000000..832eaecdf
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.properties
@@ -0,0 +1,9 @@
+spring.application.name=storage-service
+server.port=18082
+
+mysql.server.ip=127.0.0.1
+mysql.server.port=3306
+mysql.db.name=demo
+
+mysql.user.name=xxxxx
+mysql.user.password=xxxxx
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md
index e7339058c..390b567e3 100644
--- a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md
@@ -113,11 +113,11 @@ Nacos Client 从 Nacos Server 端获取数据时,调用的是此接口 `Config
在 Nacos Config Starter 中,dataId 的拼接格式如下
- ${prefix} - ${spring.active.profile} . ${file-extension}
+ ${prefix} - ${spring.profiles.active} . ${file-extension}
* `prefix` 默认为 `spring.application.name` 的值,也可以通过配置项 `spring.cloud.nacos.config.prefix`来配置。
-* `spring.active.profile` 即为当前环境对应的 profile,详情可以参考 [Spring Boot文档](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
+* `spring.profiles.active` 即为当前环境对应的 profile,详情可以参考 [Spring Boot文档](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
**注意,当 activeprofile 为空时,对应的连接符 `-` 也将不存在,dataId 的拼接格式变成 `${prefix}`.`${file-extension}`**
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md
index 58b499aef..702a51077 100644
--- a/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme.md
@@ -114,11 +114,11 @@ Nacos Client gets data from Nacos Server through this method. `ConfigService.get
In Nacos Config Starter, the splicing format of dataId is as follows
- ${prefix} - ${spring.active.profile} . ${file-extension}
+ ${prefix} - ${spring.profiles.active} . ${file-extension}
* `prefix` default value is `spring.application.name` value, which can also be configured via the configuration item `spring.cloud.nacos.config.prefix`.
-* `spring.active.profile` is the profile corresponding to the current environment. For details, please refer to [Spring Boot Doc](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
+* `spring.profiles.active` is the profile corresponding to the current environment. For details, please refer to [Spring Boot Doc](https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html#boot-features-profiles)
**Note: when the activeprofile is empty, the corresponding connector `-` will also not exist, and the splicing format of the dataId becomes `${prefix}`.`${file-extension}`**
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java
index 843f5cbe0..c8b4a1c2f 100644
--- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java
@@ -13,7 +13,6 @@ import org.springframework.web.bind.annotation.RestController;
* @author xiaojing
*/
@SpringBootApplication
-@EnableDiscoveryClient
public class ProviderApplication {
public static void main(String[] args) {
diff --git a/spring-cloud-alibaba-examples/pom.xml b/spring-cloud-alibaba-examples/pom.xml
index 6e2790f97..6cd8e7311 100644
--- a/spring-cloud-alibaba-examples/pom.xml
+++ b/spring-cloud-alibaba-examples/pom.xml
@@ -29,6 +29,10 @@
ans-example/ans-consumer-feign-example
ans-example/ans-consumer-ribbon-example
ans-example/ans-provider-example
+ fescar-example/business-service
+ fescar-example/order-service
+ fescar-example/storage-service
+ fescar-example/account-service
acm-example/acm-local-example
rocketmq-example
spring-cloud-bus-rocketmq-example
diff --git a/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml
index 868bc10cb..f3bd3370c 100644
--- a/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml
+++ b/spring-cloud-alibaba-examples/sentinel-example/sentinel-dubbo-example/sentinel-dubbo-consumer-example/pom.xml
@@ -30,7 +30,11 @@
com.alibaba.boot
dubbo-spring-boot-starter
- 0.2.0
+
+
+
+ com.alibaba
+ dubbo