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 00000000..f1283e91
--- /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 00000000..18abf0e9
--- /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 00000000..fbcaad00
--- /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 00000000..ae3d10dc
--- /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 00000000..5024fefa
--- /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 00000000..d5ba11f4
--- /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 00000000..57a0a133
--- /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 00000000..e7f80dd4
--- /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 00000000..4956e387
--- /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 00000000..28b7a373
--- /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 00000000..93ce9281
--- /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 00000000..0c4d7400
--- /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 00000000..622ae340
--- /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 00000000..4fd67f40
--- /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 00000000..9a435ff2
--- /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 00000000..1904cbd5
--- /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 00000000..7402ff97
--- /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 00000000..77ac945a
--- /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 00000000..c2627f86
--- /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 00000000..ce32e641
--- /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 00000000..d7b3d13d
--- /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 00000000..e1ad9a9d
--- /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 00000000..10ace8ec
--- /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 00000000..afdfbfa7
--- /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 00000000..c3799608
--- /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 cfea09fa..1585c4a9 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 00000000..219187bc
--- /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 00000000..893d3464
--- /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 00000000..3738fb87
--- /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 00000000..62e11cd6
--- /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 00000000..b264dd9d
--- /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 00000000..10f45c59
--- /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 00000000..6d77872a
--- /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 00000000..c0ed45fc
--- /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 00000000..039074ec
--- /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 00000000..6594793a
--- /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 00000000..65b69508
--- /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 00000000..1832ce6f
--- /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 00000000..7840c546
--- /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 00000000..8e5c7d87
--- /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 00000000..1ab0dab1
--- /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 00000000..6594793a
--- /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 00000000..2e0e0f81
--- /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 00000000..c298ca0c
--- /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 00000000..f3e417d8
--- /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 00000000..e93f6866
--- /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 00000000..bcdca22c
--- /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 00000000..2973f21a
--- /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 00000000..94bbac7f
--- /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 00000000..fd97ab2c
--- /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 00000000..4bc5989e
--- /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 00000000..832eaecd
--- /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 e7339058..390b567e 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 58b499ae..702a5107 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-consumer-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties
index fbc9736e..02b7ce32 100644
--- a/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/nacos-discovery-consumer-example/src/main/resources/application.properties
@@ -9,4 +9,5 @@ spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.eager=true
spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
-spring.cloud.sentinel.datasource.ds1.file.data-type=json
\ No newline at end of file
+spring.cloud.sentinel.datasource.ds1.file.data-type=json
+spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
\ No newline at end of file
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 843f5cbe..c8b4a1c2 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/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/pom.xml b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/pom.xml
new file mode 100644
index 00000000..bac2b278
--- /dev/null
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/pom.xml
@@ -0,0 +1,71 @@
+
+
+
+
+ org.springframework.cloud
+ nacos-gateway-example
+ 0.2.2.BUILD-SNAPSHOT
+
+ 4.0.0
+
+
+ nacos-gateway-discovery-example
+ jar
+ Example demonstrating how to use gateway with nacos
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+ 2.0.2.RELEASE
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+ ${maven-deploy-plugin.version}
+
+ true
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
+
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/GatewayApplication.java b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/GatewayApplication.java
new file mode 100644
index 00000000..c581d1ff
--- /dev/null
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/GatewayApplication.java
@@ -0,0 +1,18 @@
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+
+/**
+ * @author lengleng
+ */
+@SpringBootApplication
+@EnableDiscoveryClient
+public class GatewayApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GatewayApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/src/main/resources/application.properties
new file mode 100644
index 00000000..61394891
--- /dev/null
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-discovery-example/src/main/resources/application.properties
@@ -0,0 +1,11 @@
+server.port=18085
+spring.application.name=service-gateway
+spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
+management.endpoints.web.exposure.include=*
+
+# spring cloud route config
+spring.cloud.gateway.routes[0].id=nacos-route
+spring.cloud.gateway.routes[0].uri=lb://service-gateway-provider
+spring.cloud.gateway.routes[0].predicates[0].name=Path
+spring.cloud.gateway.routes[0].predicates[0].args[pattern]=/nacos/**
+spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/pom.xml b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/pom.xml
new file mode 100644
index 00000000..8a121fa8
--- /dev/null
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/pom.xml
@@ -0,0 +1,69 @@
+
+
+
+
+ org.springframework.cloud
+ nacos-gateway-example
+ 0.2.2.BUILD-SNAPSHOT
+
+ 4.0.0
+
+
+ nacos-gateway-provider-example
+ jar
+ Example demonstrating how to use gateway with nacos
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+ ${maven-deploy-plugin.version}
+
+ true
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
+
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java
new file mode 100644
index 00000000..843f5cbe
--- /dev/null
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/ProviderApplication.java
@@ -0,0 +1,35 @@
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xiaojing
+ */
+@SpringBootApplication
+@EnableDiscoveryClient
+public class ProviderApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ProviderApplication.class, args);
+ }
+
+ @RestController
+ class EchoController {
+ @RequestMapping(value = "/echo/{string}", method = RequestMethod.GET)
+ public String echo(@PathVariable String string) {
+ return "hello Nacos Discovery " + string;
+ }
+
+ @RequestMapping(value = "/divide", method = RequestMethod.GET)
+ public String divide(@RequestParam Integer a, @RequestParam Integer b) {
+ return String.valueOf(a / b);
+ }
+ }
+}
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/src/main/resources/application.properties b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/src/main/resources/application.properties
new file mode 100644
index 00000000..9a061092
--- /dev/null
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/nacos-gateway-provider-example/src/main/resources/application.properties
@@ -0,0 +1,4 @@
+server.port=18086
+spring.application.name=service-gateway-provider
+spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
+management.endpoints.web.exposure.include=*
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/pom.xml b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/pom.xml
new file mode 100644
index 00000000..9b7f638e
--- /dev/null
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/pom.xml
@@ -0,0 +1,45 @@
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-alibaba-examples
+ 0.2.2.BUILD-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+
+
+ nacos-gateway-example
+ pom
+ Example demonstrating how to use gateway with nacos
+
+
+
+ nacos-gateway-discovery-example
+ nacos-gateway-provider-example
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/readme-zh.md b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/readme-zh.md
new file mode 100644
index 00000000..6fc875fe
--- /dev/null
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/readme-zh.md
@@ -0,0 +1,97 @@
+# Spring Cloud Gateway、 Nacos Discovery Example
+
+## 项目说明
+
+本项目演示如何使用 Nacos Discovery Starter 、 Spring Cloud Gateway Starter 完成 Spring Cloud 服务路由。
+
+[Nacos](https://github.com/alibaba/Nacos) 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
+[Spring Cloud Gateway](https://spring.io/projects/spring-cloud-gateway) 是spring cloud 官方开源的一个在SpringMVC 上可以构建API网关的库。
+
+## 示例
+
+### 如何接入
+在启动示例进行演示之前,我们先了解一下 Spring Cloud 应用如何接入 Spring Cloud 如何接入Nacos Discovery、Spring Cloud Gateway。
+**注意 本章节只是为了便于您理解接入方式,本示例代码中已经完成接入工作,您无需再进行修改。**
+
+1. 首先,修改 pom.xml 文件,引入 Nacos Discovery Starter、Spring Cloud Gateway Starter。
+
+```xml
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+
+```
+
+2. 在应用的 /src/main/resources/application.properties 配置文件中配置 Nacos Server 地址
+
+ spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
+
+3. 在应用的 /src/main/resources/application.properties 配置文件中配置 Spring Cloud Gateway 路由
+
+```properties
+spring.cloud.gateway.routes[0].id=nacos-route
+spring.cloud.gateway.routes[0].uri=lb://service-gateway-provider
+spring.cloud.gateway.routes[0].predicates[0].name=Path
+spring.cloud.gateway.routes[0].predicates[0].args[pattern]=/nacos/**
+spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1
+```
+
+4. 使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
+
+```java
+ @SpringBootApplication
+ @EnableDiscoveryClient
+ public class GatewayApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GatewayApplication.class, args);
+ }
+
+ }
+```
+
+### 启动 Nacos Server
+
+1. 首先需要获取 Nacos Server,支持直接下载和源码构建两种方式。
+
+ 1. 直接下载:[Nacos Server 下载页](https://github.com/alibaba/nacos/releases)
+ 2. 源码构建:进入 Nacos [Github 项目页面](https://github.com/alibaba/nacos),将代码 git clone 到本地自行编译打包,[参考此文档](https://nacos.io/zh-cn/docs/quick-start.html)。**推荐使用源码构建方式以获取最新版本**
+
+2. 启动 Server,进入解压后文件夹或编译打包好的文件夹,找到如下相对文件夹 nacos/bin,并对照操作系统实际情况之下如下命令。
+
+ 1. Linux/Unix/Mac 操作系统,执行命令 `sh startup.sh -m standalone`
+ 1. Windows 操作系统,执行命令 `cmd startup.cmd`
+
+### Spring Cloud Gateway应用启动
+启动应用,支持 IDE 直接启动和编译打包后启动。
+
+1. IDE直接启动:找到 nacos-gateway-discovery-example 项目的主类 `GatewayApplication`,执行 main 方法启动应用。
+2. 打包编译后启动:在 nacos-gateway-discovery-example 项目中执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar nacos-gateway-discovery-example.jar`启动应用。
+
+### 服务提供方应用启动
+启动应用,支持 IDE 直接启动和编译打包后启动。
+1. IDE直接启动:找到 nacos-gateway-provider-example 项目的主类 `ProviderApplication`,执行 main 方法启动应用。
+2. 打包编译后启动:在 nacos-gateway-provider-example 项目中执行 `mvn clean package` 将工程编译打包,然后执行 `java -jar nacos-gateway-provider-example.jar`启动应用。
+
+### 验证
+1.
+```bash
+ curl 'http://127.0.0.1:18085/nacos/echo/hello-world'
+
+ hello Nacos Discovery hello-world⏎
+```
+1.
+```bash
+ curl 'http://127.0.0.1:18085/nacos/divide?a=6&b=2'
+
+ 3⏎
+```
+#### 更多介绍
+Nacos为用户提供包括动态服务发现,配置管理,服务管理等服务基础设施,帮助用户更灵活,更轻松地构建,交付和管理他们的微服务平台,基于Nacos, 用户可以更快速的构建以“服务”为中心的现代云原生应用。Nacos可以和Spring Cloud、Kubernetes/CNCF、Dubbo 等微服务生态无缝融合,为用户提供更卓越的体验。更多 Nacos 相关的信息,请参考 [Nacos 项目](https://github.com/alibaba/Nacos)。
+
+如果您对 Spring Cloud Nacos Discovery 有任何建议或想法,欢迎在 issue 中或者通过其他社区渠道向我们提出。
+
diff --git a/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/readme.md b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/readme.md
new file mode 100644
index 00000000..07e717b4
--- /dev/null
+++ b/spring-cloud-alibaba-examples/nacos-example/nacos-gateway-example/readme.md
@@ -0,0 +1,105 @@
+# Spring Cloud Gateway、 Nacos Discovery Example
+
+## Project Instruction
+
+This example illustrates how to use Nacos Discovery Starter、 Spring Cloud Gateway Starter implement Service route for Spring Cloud applications.
+
+[Nacos](https://github.com/alibaba/Nacos) an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications.
+[Spring Cloud Gateway](https://spring.io/projects/spring-cloud-gateway) provides a library for building an API Gateway on top of Spring MVC.
+
+
+## Demo
+
+### Connect to Nacos Discovery
+Before we start the demo, let's learn how to connect Nacos Config to a Spring Cloud application. **Note: This section is to show you how to connect to Nacos Discovery、Nacos Discovery、Spring Cloud Gateway. The configurations have been completed in the following example, so you don't need modify the code any more.**
+
+1. Add Nacos Discovery Starter、Spring Cloud Gateway Starter in the pom.xml file in your Spring Cloud project.
+
+```xml
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+
+```
+2. Add Nacos server address configurations to file /src/main/resources/application.properties.
+
+ spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
+
+3. Add Spring Cloud Gateway configurations to file /src/main/resources/application.properties.
+
+```properties
+spring.cloud.gateway.routes[0].id=nacos-route
+spring.cloud.gateway.routes[0].uri=lb://service-gateway-provider
+spring.cloud.gateway.routes[0].predicates[0].name=Path
+spring.cloud.gateway.routes[0].predicates[0].args[pattern]=/nacos/**
+spring.cloud.gateway.routes[0].filters[0]=StripPrefix=1
+```
+4. Use the @EnableDiscoveryClient annotation to turn on service registration and discovery.
+
+```java
+ @SpringBootApplication
+ @EnableDiscoveryClient
+ public class GatewayApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GatewayApplication.class, args);
+ }
+
+ }
+```
+
+### Start Nacos Server
+
+1. Install Nacos Server by downloading or build from source code.**Recommended latest version Nacos Server**
+
+ 1. Download: Download Nacos Server [download page](https://github.com/alibaba/nacos/releases)
+ 2. Build from source code: Get source code by git clone git@github.com:alibaba/Nacos.git from Github Nacos and build your code. See [build reference](https://nacos.io/en-us/docs/quick-start.html) for details.
+
+
+
+2. Unzip the downloaded file and go to the nacos/bin folder(), And according to the actual situation of the operating system, execute the following command。[see reference for more detail](https://nacos.io/en-us/docs/quick-start.html)。
+
+ 1. Linux/Unix/Mac , execute `sh startup.sh -m standalone`
+ 1. Windows , execute `cmd startup.cmd`
+
+### Start Spring Cloud Gateway Application
+Start the application in IDE or by building a fatjar.
+
+1. Start in IDE: Find main class `GatewayApplication ` in project `nacos-gateway-discovery-example`, and execute the main method.
+2. Build a fatjar:Execute command `mvn clean package` in project `nacos-gateway-discovery-example` to build a fatjar,and run command `java -jar nacos-gateway-discovery-example.jar` to start the application.
+
+
+### Start Service provider Application
+
+Start the application in IDE or by building a fatjar.
+
+1. Start in IDE: Find main class `ProviderApplication ` in project `nacos-gateway-provider-example`, and execute the main method.
+2. Build a fatjar:Execute command `mvn clean package` in project `nacos-gateway-provider-example` to build a fatjar,and run command `java -jar nacos-gateway-provider-example.jar` to start the application.
+
+
+### Verification
+1.
+```bash
+ curl 'http://127.0.0.1:18085/nacos/echo/hello-world'
+
+ hello Nacos Discovery hello-world⏎
+```
+1.
+```bash
+ curl 'http://127.0.0.1:18085/nacos/divide?a=6&b=2'
+
+ 3⏎
+```
+
+#### More introduction
+
+[Nacos ](https://github.com/alibaba/Nacos) is committed to help you discover, configure, and manage your microservices. It provides a set of simple and useful features enabling you to realize dynamic service discovery, service configuration, service metadata and traffic management.
+
+Nacos makes it easier and faster to construct, deliver and manage your microservices platform. It is the infrastructure that supports a service-centered modern application architecture with a microservices or cloud-native approach.
+
+If you have any ideas or suggestions for Nacos Discovery starter, please don't hesitate to tell us by submitting github issues.
+
diff --git a/spring-cloud-alibaba-examples/pom.xml b/spring-cloud-alibaba-examples/pom.xml
index dd03c65a..6cd8e731 100644
--- a/spring-cloud-alibaba-examples/pom.xml
+++ b/spring-cloud-alibaba-examples/pom.xml
@@ -23,11 +23,16 @@
sentinel-example/sentinel-dubbo-example/sentinel-dubbo-api
nacos-example/nacos-discovery-example
nacos-example/nacos-config-example
+ nacos-example/nacos-gateway-example
env-extension
oss-example
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/schedulerx-example/schedulerx-simple-task-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SimpleTask.java b/spring-cloud-alibaba-examples/schedulerx-example/schedulerx-simple-task-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SimpleTask.java
index e49c0a05..09055da1 100644
--- a/spring-cloud-alibaba-examples/schedulerx-example/schedulerx-simple-task-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SimpleTask.java
+++ b/spring-cloud-alibaba-examples/schedulerx-example/schedulerx-simple-task-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/SimpleTask.java
@@ -19,17 +19,22 @@ package org.springframework.cloud.alibaba.cloud.examples;
import com.alibaba.edas.schedulerx.ProcessResult;
import com.alibaba.edas.schedulerx.ScxSimpleJobContext;
import com.alibaba.edas.schedulerx.ScxSimpleJobProcessor;
+import org.springframework.beans.factory.annotation.Autowired;
/**
* @author xiaolongzuo
*/
public class SimpleTask implements ScxSimpleJobProcessor {
- @Override
- public ProcessResult process(ScxSimpleJobContext context) {
- System.out.println("-----------Hello world---------------");
- ProcessResult processResult = new ProcessResult(true);
- return processResult;
- }
+ @Autowired
+ private TestService testService;
+
+ @Override
+ public ProcessResult process(ScxSimpleJobContext context) {
+ System.out.println("-----------Hello world---------------");
+ testService.test();
+ ProcessResult processResult = new ProcessResult(true);
+ return processResult;
+ }
}
diff --git a/spring-cloud-alibaba-examples/schedulerx-example/schedulerx-simple-task-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestService.java b/spring-cloud-alibaba-examples/schedulerx-example/schedulerx-simple-task-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestService.java
new file mode 100644
index 00000000..1786d197
--- /dev/null
+++ b/spring-cloud-alibaba-examples/schedulerx-example/schedulerx-simple-task-example/src/main/java/org/springframework/cloud/alibaba/cloud/examples/TestService.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 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.stereotype.Service;
+
+/**
+ * @author xiaolongzuo
+ */
+@Service
+public class TestService {
+
+ public void test() {
+ System.out.println("---------IOC Success--------");
+ }
+}
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 868bc10c..f3bd3370 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