diff --git a/pom.xml b/pom.xml
index bd0b9c847..30dd78f5c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -91,6 +91,7 @@
spring-cloud-alibaba-sentinel-datasource
spring-cloud-alibaba-nacos-config
spring-cloud-alibaba-nacos-discovery
+ spring-cloud-alibaba-fescar
spring-cloud-stream-binder-rocketmq
spring-cloud-alibaba-nacos-config-server
spring-cloud-alicloud-context
diff --git a/spring-cloud-alibaba-dependencies/pom.xml b/spring-cloud-alibaba-dependencies/pom.xml
index b2b9f8069..16b0582c1 100644
--- a/spring-cloud-alibaba-dependencies/pom.xml
+++ b/spring-cloud-alibaba-dependencies/pom.xml
@@ -19,6 +19,7 @@
1.4.1
3.1.0
+ 0.1.3
0.6.2
0.6.1
1.0.8
@@ -176,6 +177,29 @@
+
+
+
+ com.alibaba.fescar
+ fescar-core
+ ${fescar.version}
+
+
+ com.alibaba.fescar
+ fescar-common
+ ${fescar.version}
+
+
+ com.alibaba.fescar
+ fescar-spring
+ ${fescar.version}
+
+
+ com.alibaba.fescar
+ fescar-rm-datasource
+ ${fescar.version}
+
+
com.aliyun.oss
@@ -215,6 +239,11 @@
spring-cloud-alibaba-nacos-config-server
${project.version}
+
+ org.springframework.cloud
+ spring-cloud-alibaba-fescar
+ ${project.version}
+
org.springframework.cloud
spring-cloud-alicloud-acm
@@ -258,6 +287,12 @@
${project.version}
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-fescar
+ ${project.version}
+
+
org.springframework.cloud
spring-cloud-starter-alibaba-nacos-discovery
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/account-service/pom.xml
new file mode 100644
index 000000000..219187bcf
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/pom.xml
@@ -0,0 +1,63 @@
+
+
+
+ spring-cloud-alibaba-examples
+ org.springframework.cloud
+ 0.2.2.BUILD-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+ account-service
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-fescar
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountApplication.java b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountApplication.java
new file mode 100644
index 000000000..893d34642
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountApplication.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author xiaojing
+ */
+@SpringBootApplication
+public class AccountApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AccountApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountController.java b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountController.java
new file mode 100644
index 000000000..3738fb87e
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/AccountController.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import java.util.Random;
+
+import com.alibaba.fescar.core.context.RootContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xiaojing
+ */
+@RestController
+public class AccountController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AccountController.class);
+
+ private static final String SUCCESS = "SUCCESS";
+ private static final String FAIL = "FAIL";
+
+ private final JdbcTemplate jdbcTemplate;
+ private Random random;
+
+ public AccountController(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ this.random = new Random();
+ }
+
+ @RequestMapping(value = "/account", method = RequestMethod.POST, produces = "application/json")
+ public String account(String userId, int money) {
+ LOGGER.info("Account Service ... xid: " + RootContext.getXID());
+
+ if (random.nextBoolean()) {
+ throw new RuntimeException("this is a mock Exception");
+ }
+
+ int result = jdbcTemplate.update(
+ "update account_tbl set money = money - ? where user_id = ?",
+ new Object[] { money, userId });
+ LOGGER.info("Account Service End ... ");
+ if (result == 1) {
+ return SUCCESS;
+ }
+ return FAIL;
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
new file mode 100644
index 000000000..62e11cd69
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import java.sql.SQLException;
+import java.util.Random;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.fescar.rm.datasource.DataSourceProxy;
+
+/**
+ * @author xiaojing
+ */
+@Configuration
+public class DatabaseConfiguration {
+
+ private final ApplicationContext applicationContext;
+
+ public DatabaseConfiguration(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public DruidDataSource storageDataSource() throws SQLException {
+
+ Environment environment = applicationContext.getEnvironment();
+
+ String ip = environment.getProperty("mysql.server.ip");
+ String port = environment.getProperty("mysql.server.port");
+ String dbName = environment.getProperty("mysql.db.name");
+
+ String userName = environment.getProperty("mysql.user.name");
+ String password = environment.getProperty("mysql.user.password");
+
+ DruidDataSource druidDataSource = new DruidDataSource();
+ druidDataSource.setUrl("jdbc:mysql://" + ip + ":" + port + "/" + dbName);
+ druidDataSource.setUsername(userName);
+ druidDataSource.setPassword(password);
+ druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
+ druidDataSource.setInitialSize(0);
+ druidDataSource.setMaxActive(180);
+ druidDataSource.setMaxWait(60000);
+ druidDataSource.setMinIdle(0);
+ druidDataSource.setValidationQuery("Select 'x' from DUAL");
+ druidDataSource.setTestOnBorrow(false);
+ druidDataSource.setTestOnReturn(false);
+ druidDataSource.setTestWhileIdle(true);
+ druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
+ druidDataSource.setMinEvictableIdleTimeMillis(25200000);
+ druidDataSource.setRemoveAbandoned(true);
+ druidDataSource.setRemoveAbandonedTimeout(1800);
+ druidDataSource.setLogAbandoned(true);
+ druidDataSource.setFilters("mergeStat");
+ return druidDataSource;
+ }
+
+ @Bean
+ public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) {
+ return new DataSourceProxy(druidDataSource);
+ }
+
+ @Bean
+ public JdbcTemplate jdbcTemplate(DataSourceProxy dataSourceProxy) {
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceProxy);
+
+ jdbcTemplate.update("delete from account_tbl where user_id = 'U100001'");
+ jdbcTemplate.update(
+ "insert into account_tbl(user_id, money) values ('U100001', 10000)");
+
+ return jdbcTemplate;
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.conf
new file mode 100644
index 000000000..b264dd9da
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.conf
@@ -0,0 +1,30 @@
+transport {
+ # tcp udt unix-domain-socket
+ type = "TCP"
+ #NIO NATIVE
+ server = "NIO"
+ #thread factory for netty
+ thread-factory {
+ boss-thread-prefix = "NettyBoss"
+ worker-thread-prefix = "NettyServerNIOWorker"
+ server-executor-thread-prefix = "NettyServerBizHandler"
+ share-boss-worker = false
+ client-selector-thread-prefix = "NettyClientSelector"
+ client-selector-thread-size = 1
+ client-worker-thread-prefix = "NettyClientWorkerThread"
+ # netty boss thread size,will not be used for UDT
+ boss-thread-size = 1
+ #auto default pin or 8
+ worker-thread-size = 8
+ }
+}
+service {
+ #vgroup->rgroup
+ vgroup_mapping.account-service-fescar-service-group = "localRgroup"
+ #only support single node
+ localRgroup.grouplist = "127.0.0.1:8091"
+ #degrade current not support
+ enableDegrade = false
+ #disable
+ disable = false
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.properties
new file mode 100644
index 000000000..10f45c59a
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/account-service/src/main/resources/application.properties
@@ -0,0 +1,9 @@
+spring.application.name=account-service
+server.port=18084
+
+mysql.server.ip=127.0.0.1
+mysql.server.port=3306
+mysql.db.name=demo
+
+mysql.user.name=xxxxx
+mysql.user.password=xxxxx
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/business-service/pom.xml
new file mode 100644
index 000000000..6d77872a2
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+ spring-cloud-alibaba-examples
+ org.springframework.cloud
+ 0.2.2.BUILD-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+ business-service
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-fescar
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-hystrix
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/BusinessApplication.java b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/BusinessApplication.java
new file mode 100644
index 000000000..c0ed45fc2
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/BusinessApplication.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author xiaojing
+ */
+@SpringBootApplication
+@EnableFeignClients
+public class BusinessApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(BusinessApplication.class, args);
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+ @FeignClient(value = "storage", url = "http://127.0.0.1:18082")
+ public interface StorageService {
+
+ @RequestMapping(path = "/storage/{commodityCode}/{count}")
+ String storage(@RequestParam("commodityCode") String commodityCode,
+ @RequestParam("count") int count);
+
+ }
+
+ @FeignClient(value = "order", url = "http://127.0.0.1:18083")
+ public interface OrderService {
+
+ @RequestMapping(path = "/order", method = RequestMethod.POST)
+ String order(@RequestParam("userId") String userId,
+ @RequestParam("commodityCode") String commodityCode,
+ @RequestParam("orderCount") int orderCount);
+
+ }
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/HomeController.java b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/HomeController.java
new file mode 100644
index 000000000..039074ec0
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/HomeController.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import com.alibaba.fescar.spring.annotation.GlobalTransactional;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.alibaba.cloud.examples.BusinessApplication.OrderService;
+import org.springframework.cloud.alibaba.cloud.examples.BusinessApplication.StorageService;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author xiaojing
+ */
+@RestController
+public class HomeController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class);
+
+ private static final String SUCCESS = "SUCCESS";
+ private static final String FAIL = "FAIL";
+ private static final String USER_ID = "U100001";
+ private static final String COMMODITY_CODE = "C00321";
+ private static final int ORDER_COUNT = 2;
+
+ private final RestTemplate restTemplate;
+ private final OrderService orderService;
+ private final StorageService storageService;
+
+ public HomeController(RestTemplate restTemplate, OrderService orderService,
+ StorageService storageService) {
+ this.restTemplate = restTemplate;
+ this.orderService = orderService;
+ this.storageService = storageService;
+ }
+
+ @GlobalTransactional(timeoutMills = 300000, name = "spring-cloud-demo-tx")
+ @RequestMapping(value = "/fescar/rest", method = RequestMethod.GET, produces = "application/json")
+ public String rest() {
+
+ String result = restTemplate.getForObject(
+ "http://127.0.0.1:18082/storage/" + COMMODITY_CODE + "/" + ORDER_COUNT,
+ String.class);
+
+ if (!SUCCESS.equals(result)) {
+ throw new RuntimeException();
+ }
+
+ String url = "http://127.0.0.1:18083/order";
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+
+ MultiValueMap map = new LinkedMultiValueMap();
+ map.add("userId", USER_ID);
+ map.add("commodityCode", COMMODITY_CODE);
+ map.add("orderCount", ORDER_COUNT + "");
+
+ HttpEntity> request = new HttpEntity>(
+ map, headers);
+
+ ResponseEntity response = restTemplate.postForEntity(url, request,
+ String.class);
+
+ result = response.getBody();
+
+ if (!SUCCESS.equals(result)) {
+ throw new RuntimeException();
+ }
+
+ return SUCCESS;
+ }
+
+ @GlobalTransactional(timeoutMills = 300000, name = "spring-cloud-demo-tx")
+ @RequestMapping(value = "/fescar/feign", method = RequestMethod.GET, produces = "application/json")
+ public String feign() {
+
+ String result = storageService.storage(COMMODITY_CODE, ORDER_COUNT);
+
+ if (!SUCCESS.equals(result)) {
+ throw new RuntimeException();
+ }
+
+ result = orderService.order(USER_ID, COMMODITY_CODE, ORDER_COUNT);
+
+ if (!SUCCESS.equals(result)) {
+ throw new RuntimeException();
+ }
+
+ return SUCCESS;
+
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java
new file mode 100644
index 000000000..6594793a3
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import java.io.Serializable;
+
+public class Order implements Serializable {
+ public long id;
+ public String userId;
+ public String commodityCode;
+ public int count;
+ public int money;
+
+ @Override
+ public String toString() {
+ return "Order{" + "id=" + id + ", userId='" + userId + '\'' + ", commodityCode='"
+ + commodityCode + '\'' + ", count=" + count + ", money=" + money + '}';
+ }
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.conf
new file mode 100644
index 000000000..65b695084
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.conf
@@ -0,0 +1,30 @@
+transport {
+ # tcp udt unix-domain-socket
+ type = "TCP"
+ #NIO NATIVE
+ server = "NIO"
+ #thread factory for netty
+ thread-factory {
+ boss-thread-prefix = "NettyBoss"
+ worker-thread-prefix = "NettyServerNIOWorker"
+ server-executor-thread-prefix = "NettyServerBizHandler"
+ share-boss-worker = false
+ client-selector-thread-prefix = "NettyClientSelector"
+ client-selector-thread-size = 1
+ client-worker-thread-prefix = "NettyClientWorkerThread"
+ # netty boss thread size,will not be used for UDT
+ boss-thread-size = 1
+ #auto default pin or 8
+ worker-thread-size = 8
+ }
+}
+service {
+ #vgroup->rgroup
+ vgroup_mapping.business-service-fescar-service-group = "localRgroup"
+ #only support single node
+ localRgroup.grouplist = "127.0.0.1:8091"
+ #degrade current not support
+ enableDegrade = false
+ #disable
+ disable = false
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.properties
new file mode 100644
index 000000000..1832ce6f5
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/business-service/src/main/resources/application.properties
@@ -0,0 +1,8 @@
+server.port=18081
+spring.application.name=business-service
+# The following configuration can be omitted.
+
+#feign.hystrix.enabled=true
+#feign.sentinel.enabled=true
+
+logging.level.com.alibaba.fescar=debug
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/order-service/pom.xml
new file mode 100644
index 000000000..7840c5462
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/pom.xml
@@ -0,0 +1,63 @@
+
+
+
+ spring-cloud-alibaba-examples
+ org.springframework.cloud
+ 0.2.2.BUILD-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+ order-service
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-fescar
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
new file mode 100644
index 000000000..8e5c7d87b
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import java.sql.SQLException;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.fescar.rm.datasource.DataSourceProxy;
+
+/**
+ * @author xiaojing
+ */
+@Configuration
+public class DatabaseConfiguration {
+
+ private final ApplicationContext applicationContext;
+
+ public DatabaseConfiguration(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public DruidDataSource storageDataSource() throws SQLException {
+
+ Environment env = applicationContext.getEnvironment();
+
+ String ip = env.getProperty("mysql.server.ip");
+ String port = env.getProperty("mysql.server.port");
+ String dbName = env.getProperty("mysql.db.name");
+
+ String userName = env.getProperty("mysql.user.name");
+ String password = env.getProperty("mysql.user.password");
+
+ DruidDataSource druidDataSource = new DruidDataSource();
+ druidDataSource.setUrl("jdbc:mysql://" + ip + ":" + port + "/" + dbName);
+ druidDataSource.setUsername(userName);
+ druidDataSource.setPassword(password);
+ druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
+ druidDataSource.setInitialSize(0);
+ druidDataSource.setMaxActive(180);
+ druidDataSource.setMaxWait(60000);
+ druidDataSource.setMinIdle(0);
+ druidDataSource.setValidationQuery("Select 'x' from DUAL");
+ druidDataSource.setTestOnBorrow(false);
+ druidDataSource.setTestOnReturn(false);
+ druidDataSource.setTestWhileIdle(true);
+ druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
+ druidDataSource.setMinEvictableIdleTimeMillis(25200000);
+ druidDataSource.setRemoveAbandoned(true);
+ druidDataSource.setRemoveAbandonedTimeout(1800);
+ druidDataSource.setLogAbandoned(true);
+ druidDataSource.setFilters("mergeStat");
+ return druidDataSource;
+ }
+
+ @Bean
+ public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) {
+ return new DataSourceProxy(druidDataSource);
+ }
+
+ @Bean
+ public JdbcTemplate jdbcTemplate(DataSourceProxy dataSourceProxy) {
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceProxy);
+
+ jdbcTemplate.execute("TRUNCATE TABLE order_tbl");
+
+ return jdbcTemplate;
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OderApplication.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OderApplication.java
new file mode 100644
index 000000000..1ab0dab11
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OderApplication.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author xiaojing
+ */
+@SpringBootApplication
+public class OderApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(OderApplication.class, args);
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java
new file mode 100644
index 000000000..6594793a3
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/Order.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import java.io.Serializable;
+
+public class Order implements Serializable {
+ public long id;
+ public String userId;
+ public String commodityCode;
+ public int count;
+ public int money;
+
+ @Override
+ public String toString() {
+ return "Order{" + "id=" + id + ", userId='" + userId + '\'' + ", commodityCode='"
+ + commodityCode + '\'' + ", count=" + count + ", money=" + money + '}';
+ }
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OrderController.java b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OrderController.java
new file mode 100644
index 000000000..2e0e0f81c
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/OrderController.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Random;
+
+import com.alibaba.fescar.core.context.RootContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.PreparedStatementCreator;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+import org.springframework.jdbc.support.KeyHolder;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author xiaojing
+ */
+@RestController
+public class OrderController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(OrderController.class);
+ private static final String SUCCESS = "SUCCESS";
+ private static final String FAIL = "FAIL";
+ private static final String USER_ID = "U100001";
+ private static final String COMMODITY_CODE = "C00321";
+
+ private final JdbcTemplate jdbcTemplate;
+ private final RestTemplate restTemplate;
+ private Random random;
+
+ public OrderController(JdbcTemplate jdbcTemplate, RestTemplate restTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ this.restTemplate = restTemplate;
+ this.random = new Random();
+ }
+
+ @RequestMapping(value = "/order", method = RequestMethod.POST, produces = "application/json")
+ public String order(String userId, String commodityCode, int orderCount) {
+ LOGGER.info("Order Service Begin ... xid: " + RootContext.getXID());
+
+ int orderMoney = calculate(commodityCode, orderCount);
+
+ invokerAccountService(orderMoney);
+
+ final Order order = new Order();
+ order.userId = userId;
+ order.commodityCode = commodityCode;
+ order.count = orderCount;
+ order.money = orderMoney;
+
+ KeyHolder keyHolder = new GeneratedKeyHolder();
+
+ int result = jdbcTemplate.update(new PreparedStatementCreator() {
+
+ @Override
+ public PreparedStatement createPreparedStatement(Connection con)
+ throws SQLException {
+ PreparedStatement pst = con.prepareStatement(
+ "insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)",
+ PreparedStatement.RETURN_GENERATED_KEYS);
+ pst.setObject(1, order.userId);
+ pst.setObject(2, order.commodityCode);
+ pst.setObject(3, order.count);
+ pst.setObject(4, order.money);
+ return pst;
+ }
+ }, keyHolder);
+
+ order.id = (long) keyHolder.getKey();
+
+ if (random.nextBoolean()) {
+ throw new RuntimeException("this is a mock Exception");
+ }
+
+ LOGGER.info("Order Service End ... Created " + order);
+
+ if (result == 1) {
+ return SUCCESS;
+ }
+ return FAIL;
+ }
+
+ private int calculate(String commodityId, int orderCount) {
+ return 2 * orderCount;
+ }
+
+ private void invokerAccountService(int orderMoney) {
+ String url = "http://127.0.0.1:18084/account";
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+
+ MultiValueMap map = new LinkedMultiValueMap();
+
+ map.add("userId", USER_ID);
+ map.add("money", orderMoney + "");
+
+ HttpEntity> request = new HttpEntity>(
+ map, headers);
+
+ ResponseEntity response = restTemplate.postForEntity(url, request,
+ String.class);
+ }
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.conf
new file mode 100644
index 000000000..c298ca0c2
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.conf
@@ -0,0 +1,30 @@
+transport {
+ # tcp udt unix-domain-socket
+ type = "TCP"
+ #NIO NATIVE
+ server = "NIO"
+ #thread factory for netty
+ thread-factory {
+ boss-thread-prefix = "NettyBoss"
+ worker-thread-prefix = "NettyServerNIOWorker"
+ server-executor-thread-prefix = "NettyServerBizHandler"
+ share-boss-worker = false
+ client-selector-thread-prefix = "NettyClientSelector"
+ client-selector-thread-size = 1
+ client-worker-thread-prefix = "NettyClientWorkerThread"
+ # netty boss thread size,will not be used for UDT
+ boss-thread-size = 1
+ #auto default pin or 8
+ worker-thread-size = 8
+ }
+}
+service {
+ #vgroup->rgroup
+ vgroup_mapping.order-service-fescar-service-group = "localRgroup"
+ #only support single node
+ localRgroup.grouplist = "127.0.0.1:8091"
+ #degrade current not support
+ enableDegrade = false
+ #disable
+ disable = false
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.properties
new file mode 100644
index 000000000..f3e417d8d
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/order-service/src/main/resources/application.properties
@@ -0,0 +1,9 @@
+spring.application.name=order-service
+server.port=18083
+
+mysql.server.ip=127.0.0.1
+mysql.server.port=3306
+mysql.db.name=demo
+
+mysql.user.name=xxxxx
+mysql.user.password=xxxxx
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/readme-zh.md b/spring-cloud-alibaba-examples/fescar-example/readme-zh.md
new file mode 100644
index 000000000..be3919497
--- /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. Create UNDO_LOG table
+
+1. Create tables for examples business
+
+1. Start 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 同时使用的场景。
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/pom.xml b/spring-cloud-alibaba-examples/fescar-example/storage-service/pom.xml
new file mode 100644
index 000000000..bcdca22c0
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/pom.xml
@@ -0,0 +1,68 @@
+
+
+
+ spring-cloud-alibaba-examples
+ org.springframework.cloud
+ 0.2.2.BUILD-SNAPSHOT
+ ../../pom.xml
+
+ 4.0.0
+ storage-service
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-fescar
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ com.alibaba
+ druid
+ 1.1.10
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+
+ mysql
+ mysql-connector-java
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ false
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
new file mode 100644
index 000000000..2973f21ae
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/DatabaseConfiguration.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import java.sql.SQLException;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.fescar.rm.datasource.DataSourceProxy;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * @author xiaojing
+ */
+@Configuration
+public class DatabaseConfiguration {
+
+ private final ApplicationContext applicationContext;
+
+ public DatabaseConfiguration(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ @Bean(initMethod = "init", destroyMethod = "close")
+ public DruidDataSource storageDataSource() throws SQLException {
+
+ Environment environment = applicationContext.getEnvironment();
+
+ String ip = environment.getProperty("mysql.server.ip");
+ String port = environment.getProperty("mysql.server.port");
+ String dbName = environment.getProperty("mysql.db.name");
+
+ String userName = environment.getProperty("mysql.user.name");
+ String password = environment.getProperty("mysql.user.password");
+
+ DruidDataSource druidDataSource = new DruidDataSource();
+ druidDataSource.setUrl("jdbc:mysql://" + ip + ":" + port + "/" + dbName);
+ druidDataSource.setUsername(userName);
+ druidDataSource.setPassword(password);
+ druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
+ druidDataSource.setInitialSize(0);
+ druidDataSource.setMaxActive(180);
+ druidDataSource.setMaxWait(60000);
+ druidDataSource.setMinIdle(0);
+ druidDataSource.setValidationQuery("Select 'x' from DUAL");
+ druidDataSource.setTestOnBorrow(false);
+ druidDataSource.setTestOnReturn(false);
+ druidDataSource.setTestWhileIdle(true);
+ druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
+ druidDataSource.setMinEvictableIdleTimeMillis(25200000);
+ druidDataSource.setRemoveAbandoned(true);
+ druidDataSource.setRemoveAbandonedTimeout(1800);
+ druidDataSource.setLogAbandoned(true);
+ druidDataSource.setFilters("mergeStat");
+ return druidDataSource;
+ }
+
+ @Bean
+ public DataSourceProxy dataSourceProxy(DruidDataSource druidDataSource) {
+ return new DataSourceProxy(druidDataSource);
+ }
+
+ @Bean
+ public JdbcTemplate jdbcTemplate(DataSourceProxy dataSourceProxy) {
+
+ JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceProxy);
+
+ jdbcTemplate.update("delete from storage_tbl where commodity_code = 'C00321'");
+ jdbcTemplate.update(
+ "insert into storage_tbl(commodity_code, count) values ('C00321', 100)");
+
+ return jdbcTemplate;
+
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageApplication.java b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageApplication.java
new file mode 100644
index 000000000..94bbac7f4
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageApplication.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * @author xiaojing
+ */
+@SpringBootApplication
+public class StorageApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(StorageApplication.class, args);
+ }
+
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageController.java b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageController.java
new file mode 100644
index 000000000..fd97ab2c8
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/java/org/springframework/cloud/alibaba/cloud/examples/StorageController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.alibaba.cloud.examples;
+
+import com.alibaba.fescar.core.context.RootContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author xiaojing
+ */
+@RestController
+public class StorageController {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(StorageController.class);
+
+ private static final String SUCCESS = "SUCCESS";
+ private static final String FAIL = "FAIL";
+
+ private final JdbcTemplate jdbcTemplate;
+
+ public StorageController(JdbcTemplate jdbcTemplate) {
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ @RequestMapping(value = "/storage/{commodityCode}/{count}", method = RequestMethod.GET, produces = "application/json")
+ public String echo(@PathVariable String commodityCode, @PathVariable int count) {
+ LOGGER.info("Storage Service Begin ... xid: " + RootContext.getXID());
+ int result = jdbcTemplate.update(
+ "update storage_tbl set count = count - ? where commodity_code = ?",
+ new Object[] { count, commodityCode });
+ LOGGER.info("Storage Service End ... ");
+ if (result == 1) {
+ return SUCCESS;
+ }
+ return FAIL;
+ }
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.conf b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.conf
new file mode 100644
index 000000000..4bc5989e1
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.conf
@@ -0,0 +1,30 @@
+transport {
+ # tcp udt unix-domain-socket
+ type = "TCP"
+ #NIO NATIVE
+ server = "NIO"
+ #thread factory for netty
+ thread-factory {
+ boss-thread-prefix = "NettyBoss"
+ worker-thread-prefix = "NettyServerNIOWorker"
+ server-executor-thread-prefix = "NettyServerBizHandler"
+ share-boss-worker = false
+ client-selector-thread-prefix = "NettyClientSelector"
+ client-selector-thread-size = 1
+ client-worker-thread-prefix = "NettyClientWorkerThread"
+ # netty boss thread size,will not be used for UDT
+ boss-thread-size = 1
+ #auto default pin or 8
+ worker-thread-size = 8
+ }
+}
+service {
+ #vgroup->rgroup
+ vgroup_mapping.storage-service-fescar-service-group = "localRgroup"
+ #only support single node
+ localRgroup.grouplist = "127.0.0.1:8091"
+ #degrade current not support
+ enableDegrade = false
+ #disable
+ disable = false
+}
diff --git a/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.properties b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.properties
new file mode 100644
index 000000000..832eaecdf
--- /dev/null
+++ b/spring-cloud-alibaba-examples/fescar-example/storage-service/src/main/resources/application.properties
@@ -0,0 +1,9 @@
+spring.application.name=storage-service
+server.port=18082
+
+mysql.server.ip=127.0.0.1
+mysql.server.port=3306
+mysql.db.name=demo
+
+mysql.user.name=xxxxx
+mysql.user.password=xxxxx
\ No newline at end of file
diff --git a/spring-cloud-alibaba-examples/pom.xml b/spring-cloud-alibaba-examples/pom.xml
index 6e2790f97..6cd8e7311 100644
--- a/spring-cloud-alibaba-examples/pom.xml
+++ b/spring-cloud-alibaba-examples/pom.xml
@@ -29,6 +29,10 @@
ans-example/ans-consumer-feign-example
ans-example/ans-consumer-ribbon-example
ans-example/ans-provider-example
+ fescar-example/business-service
+ fescar-example/order-service
+ fescar-example/storage-service
+ fescar-example/account-service
acm-example/acm-local-example
rocketmq-example
spring-cloud-bus-rocketmq-example
diff --git a/spring-cloud-alibaba-fescar/pom.xml b/spring-cloud-alibaba-fescar/pom.xml
new file mode 100644
index 000000000..15613f576
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/pom.xml
@@ -0,0 +1,117 @@
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-alibaba
+ 0.2.2.BUILD-SNAPSHOT
+
+ 4.0.0
+
+ org.springframework.cloud
+ spring-cloud-alibaba-fescar
+ Spring Cloud Alibaba Fescar
+
+
+
+
+ com.alibaba.fescar
+ fescar-core
+
+
+ com.alibaba.fescar
+ fescar-common
+
+
+ com.alibaba.fescar
+ fescar-spring
+
+
+ com.alibaba.fescar
+ fescar-rm-datasource
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-openfeign
+ provided
+ true
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba-sentinel
+ provided
+ true
+
+
+
+ org.springframework.cloud
+ spring-cloud-commons
+ true
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-ribbon
+ provided
+ true
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+
+ org.springframework.boot
+ spring-boot-actuator
+ provided
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-actuator-autoconfigure
+ provided
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ provided
+ true
+
+
+
+ org.springframework.boot
+ spring-boot
+ provided
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+ provided
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ provided
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/FescarProperties.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/FescarProperties.java
new file mode 100644
index 000000000..f7847d968
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/FescarProperties.java
@@ -0,0 +1,42 @@
+/*
+ * 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.fescar;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * @author xiaojing
+ */
+@ConfigurationProperties("spring.cloud.alibaba.fescar")
+public class FescarProperties {
+
+ // todo support config Fescar server information
+
+ /**
+ * Fescar tx service group.default is ${spring.application.name}-fescar-service-group.
+ */
+ private String txServiceGroup;
+
+ public String getTxServiceGroup() {
+ return txServiceGroup;
+ }
+
+ public void setTxServiceGroup(String txServiceGroup) {
+ this.txServiceGroup = txServiceGroup;
+ }
+
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/GlobalTransactionAutoConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/GlobalTransactionAutoConfiguration.java
new file mode 100644
index 000000000..d876ad3bd
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/GlobalTransactionAutoConfiguration.java
@@ -0,0 +1,60 @@
+/*
+ * 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.fescar;
+
+import com.alibaba.fescar.spring.annotation.GlobalTransactionScanner;
+
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.StringUtils;
+
+/**
+ * @author xiaojing
+ */
+
+@Configuration
+@EnableConfigurationProperties(FescarProperties.class)
+public class GlobalTransactionAutoConfiguration {
+
+ private final ApplicationContext applicationContext;
+
+ private final FescarProperties fescarProperties;
+
+ public GlobalTransactionAutoConfiguration(ApplicationContext applicationContext,
+ FescarProperties fescarProperties) {
+ this.applicationContext = applicationContext;
+ this.fescarProperties = fescarProperties;
+ }
+
+ @Bean
+ public GlobalTransactionScanner globalTransactionScanner() {
+
+ String applicationName = applicationContext.getEnvironment()
+ .getProperty("spring.application.name");
+
+ String txServiceGroup = fescarProperties.getTxServiceGroup();
+
+ if (StringUtils.isEmpty(txServiceGroup)) {
+ txServiceGroup = applicationName + "-fescar-service-group";
+ fescarProperties.setTxServiceGroup(txServiceGroup);
+ }
+
+ return new GlobalTransactionScanner(applicationName, txServiceGroup);
+ }
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java
new file mode 100644
index 000000000..9d7b685c3
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarBeanPostProcessor.java
@@ -0,0 +1,44 @@
+/*
+ * 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.fescar.feign;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+/**
+ * @author xiaojing
+ */
+final class FescarBeanPostProcessor implements BeanPostProcessor {
+
+ private final FescarFeignObjectWrapper eagleEyeFeignObjectWrapper;
+
+ FescarBeanPostProcessor(FescarFeignObjectWrapper eagleEyeFeignObjectWrapper) {
+ this.eagleEyeFeignObjectWrapper = eagleEyeFeignObjectWrapper;
+ }
+
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName)
+ throws BeansException {
+ return this.eagleEyeFeignObjectWrapper.wrap(bean);
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+ return bean;
+ }
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java
new file mode 100644
index 000000000..39afc2792
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarContextBeanPostProcessor.java
@@ -0,0 +1,59 @@
+/*
+ * 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.fescar.feign;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.cloud.openfeign.FeignContext;
+
+/**
+ * @author xiaojing
+ */
+public class FescarContextBeanPostProcessor implements BeanPostProcessor {
+
+ private final BeanFactory beanFactory;
+ private FescarFeignObjectWrapper eagleEyeFeignObjectWrapper;
+
+ FescarContextBeanPostProcessor(BeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName)
+ throws BeansException {
+ if (bean instanceof FeignContext && !(bean instanceof FescarFeignContext)) {
+ return new FescarFeignContext(getEagleEyeFeignObjectWrapper(),
+ (FeignContext) bean);
+ }
+ return bean;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+ return bean;
+ }
+
+ private FescarFeignObjectWrapper getEagleEyeFeignObjectWrapper() {
+ if (this.eagleEyeFeignObjectWrapper == null) {
+ this.eagleEyeFeignObjectWrapper = this.beanFactory
+ .getBean(FescarFeignObjectWrapper.class);
+ }
+ return this.eagleEyeFeignObjectWrapper;
+ }
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignBuilder.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignBuilder.java
new file mode 100644
index 000000000..acab33ff9
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignBuilder.java
@@ -0,0 +1,34 @@
+/*
+ * 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.fescar.feign;
+
+import org.springframework.beans.factory.BeanFactory;
+
+import feign.Feign;
+
+/**
+ * @author xiaojing
+ */
+final class FescarFeignBuilder {
+
+ private FescarFeignBuilder() {
+ }
+
+ static Feign.Builder builder(BeanFactory beanFactory) {
+ return Feign.builder().client(new FescarFeignClient(beanFactory));
+ }
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClient.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClient.java
new file mode 100644
index 000000000..9fc9d527c
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClient.java
@@ -0,0 +1,85 @@
+/*
+ * 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.fescar.feign;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.alibaba.fescar.core.context.RootContext;
+
+import org.springframework.beans.factory.BeanFactory;
+
+import feign.Client;
+import feign.Request;
+import feign.Response;
+import org.springframework.util.StringUtils;
+
+/**
+ * @author xiaojing
+ */
+public class FescarFeignClient implements Client {
+
+ private final Client delegate;
+ private final BeanFactory beanFactory;
+
+ FescarFeignClient(BeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ this.delegate = new Client.Default(null, null);
+ }
+
+ FescarFeignClient(BeanFactory beanFactory, Client delegate) {
+ this.delegate = delegate;
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ public Response execute(Request request, Request.Options options) throws IOException {
+
+ Request modifiedRequest = getModifyRequest(request);
+
+ try {
+ return this.delegate.execute(modifiedRequest, options);
+ }
+ finally {
+
+ }
+ }
+
+ private Request getModifyRequest(Request request) {
+
+ String xid = RootContext.getXID();
+
+ if (StringUtils.isEmpty(xid)) {
+ return request;
+ }
+
+ Map> headers = new HashMap<>();
+ headers.putAll(request.headers());
+
+ List fescarXid = new ArrayList<>();
+ fescarXid.add(xid);
+ headers.put(RootContext.KEY_XID, fescarXid);
+
+ return Request.create(request.method(), request.url(), headers, request.body(),
+ request.charset());
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java
new file mode 100644
index 000000000..cdf1f6863
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignClientAutoConfiguration.java
@@ -0,0 +1,85 @@
+/*
+ * 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.fescar.feign;
+
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.openfeign.FeignAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Scope;
+
+import feign.Client;
+import feign.Feign;
+
+/**
+ * @author xiaojing
+ */
+
+@Configuration
+@ConditionalOnClass(Client.class)
+@AutoConfigureBefore(FeignAutoConfiguration.class)
+public class FescarFeignClientAutoConfiguration {
+
+ @Bean
+ @Scope("prototype")
+ @ConditionalOnClass(name = "com.netflix.hystrix.HystrixCommand")
+ @ConditionalOnProperty(name = "feign.hystrix.enabled", havingValue = "true")
+ Feign.Builder feignHystrixBuilder(BeanFactory beanFactory) {
+ return FescarHystrixFeignBuilder.builder(beanFactory);
+ }
+
+ @Bean
+ @Scope("prototype")
+ @ConditionalOnClass(name = "com.alibaba.csp.sentinel.SphU")
+ @ConditionalOnProperty(name = "feign.sentinel.enabled", havingValue = "true")
+ Feign.Builder feignSentinelBuilder(BeanFactory beanFactory) {
+ return FescarSentinelFeignBuilder.builder(beanFactory);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ @Scope("prototype")
+ Feign.Builder feignBuilder(BeanFactory beanFactory) {
+ return FescarFeignBuilder.builder(beanFactory);
+ }
+
+ @Configuration
+ protected static class FeignBeanPostProcessorConfiguration {
+
+ @Bean
+ FescarBeanPostProcessor eagleEyeBeanPostProcessor(
+ FescarFeignObjectWrapper eagleEyeFeignObjectWrapper) {
+ return new FescarBeanPostProcessor(eagleEyeFeignObjectWrapper);
+ }
+
+ @Bean
+ FescarContextBeanPostProcessor eagleEyeContextBeanPostProcessor(
+ BeanFactory beanFactory) {
+ return new FescarContextBeanPostProcessor(beanFactory);
+ }
+
+ @Bean
+ FescarFeignObjectWrapper eagleEyeFeignObjectWrapper(BeanFactory beanFactory) {
+ return new FescarFeignObjectWrapper(beanFactory);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java
new file mode 100644
index 000000000..1ae5ea8d4
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignContext.java
@@ -0,0 +1,67 @@
+/*
+ * 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.fescar.feign;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import feign.Client;
+import org.springframework.cloud.openfeign.FeignContext;
+
+/**
+ *
+ * @author xiaojing
+ */
+public class FescarFeignContext extends FeignContext {
+
+ private final FescarFeignObjectWrapper fescarFeignObjectWrapper;
+ private final FeignContext delegate;
+
+ FescarFeignContext(FescarFeignObjectWrapper eagleEyeFeignObjectWrapper,
+ FeignContext delegate) {
+ this.fescarFeignObjectWrapper = eagleEyeFeignObjectWrapper;
+ this.delegate = delegate;
+ }
+
+ @Override
+ public T getInstance(String name, Class type) {
+ T object = this.delegate.getInstance(name, type);
+ if (object instanceof Client) {
+ return object;
+ }
+ return (T) this.fescarFeignObjectWrapper.wrap(object);
+ }
+
+ @Override
+ public Map getInstances(String name, Class type) {
+ Map instances = this.delegate.getInstances(name, type);
+ if (instances == null) {
+ return null;
+ }
+ Map convertedInstances = new HashMap<>();
+ for (Map.Entry entry : instances.entrySet()) {
+ if (entry.getValue() instanceof Client) {
+ convertedInstances.put(entry.getKey(), entry.getValue());
+ }
+ else {
+ convertedInstances.put(entry.getKey(),
+ (T) this.fescarFeignObjectWrapper.wrap(entry.getValue()));
+ }
+ }
+ return convertedInstances;
+ }
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignObjectWrapper.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignObjectWrapper.java
new file mode 100644
index 000000000..9b42b2f98
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarFeignObjectWrapper.java
@@ -0,0 +1,67 @@
+/*
+ * 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.fescar.feign;
+
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
+
+import feign.Client;
+import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
+import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
+
+/**
+ * @author xiaojing
+ */
+public class FescarFeignObjectWrapper {
+
+ private final BeanFactory beanFactory;
+
+ private CachingSpringLoadBalancerFactory cachingSpringLoadBalancerFactory;
+ private SpringClientFactory springClientFactory;
+
+ FescarFeignObjectWrapper(BeanFactory beanFactory) {
+ this.beanFactory = beanFactory;
+ }
+
+ Object wrap(Object bean) {
+ if (bean instanceof Client && !(bean instanceof FescarFeignClient)) {
+ if (bean instanceof LoadBalancerFeignClient) {
+ LoadBalancerFeignClient client = ((LoadBalancerFeignClient) bean);
+ return new FescarLoadBalancerFeignClient(client.getDelegate(), factory(),
+ clientFactory(), this.beanFactory);
+ }
+ return new FescarFeignClient(this.beanFactory, (Client) bean);
+ }
+ return bean;
+ }
+
+ CachingSpringLoadBalancerFactory factory() {
+ if (this.cachingSpringLoadBalancerFactory == null) {
+ this.cachingSpringLoadBalancerFactory = this.beanFactory
+ .getBean(CachingSpringLoadBalancerFactory.class);
+ }
+ return this.cachingSpringLoadBalancerFactory;
+ }
+
+ SpringClientFactory clientFactory() {
+ if (this.springClientFactory == null) {
+ this.springClientFactory = this.beanFactory
+ .getBean(SpringClientFactory.class);
+ }
+ return this.springClientFactory;
+ }
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarHystrixFeignBuilder.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarHystrixFeignBuilder.java
new file mode 100644
index 000000000..b67a9d840
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarHystrixFeignBuilder.java
@@ -0,0 +1,37 @@
+/*
+ * 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.fescar.feign;
+
+import feign.Retryer;
+import feign.hystrix.HystrixFeign;
+import org.springframework.beans.factory.BeanFactory;
+
+import feign.Feign;
+
+/**
+ * @author xiaojing
+ */
+final class FescarHystrixFeignBuilder {
+
+ private FescarHystrixFeignBuilder() {
+ }
+
+ static Feign.Builder builder(BeanFactory beanFactory) {
+ return HystrixFeign.builder().retryer(Retryer.NEVER_RETRY)
+ .client(new FescarFeignClient(beanFactory));
+ }
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarLoadBalancerFeignClient.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarLoadBalancerFeignClient.java
new file mode 100644
index 000000000..7f00d0585
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarLoadBalancerFeignClient.java
@@ -0,0 +1,53 @@
+/*
+ * 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.fescar.feign;
+
+import java.io.IOException;
+
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
+
+import feign.Client;
+import feign.Request;
+import feign.Response;
+import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
+import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
+
+/**
+ * @author xiaojing
+ */
+public class FescarLoadBalancerFeignClient extends LoadBalancerFeignClient {
+
+ private final BeanFactory beanFactory;
+
+ FescarLoadBalancerFeignClient(Client delegate,
+ CachingSpringLoadBalancerFactory lbClientFactory,
+ SpringClientFactory clientFactory, BeanFactory beanFactory) {
+ super(wrap(delegate, beanFactory), lbClientFactory, clientFactory);
+ this.beanFactory = beanFactory;
+ }
+
+ @Override
+ public Response execute(Request request, Request.Options options) throws IOException {
+ return super.execute(request, options);
+ }
+
+ private static Client wrap(Client delegate, BeanFactory beanFactory) {
+ return (Client) new FescarFeignObjectWrapper(beanFactory).wrap(delegate);
+ }
+
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarSentinelFeignBuilder.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarSentinelFeignBuilder.java
new file mode 100644
index 000000000..42f632144
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/FescarSentinelFeignBuilder.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.fescar.feign;
+
+import org.springframework.beans.factory.BeanFactory;
+
+import feign.Feign;
+import feign.Retryer;
+import feign.hystrix.HystrixFeign;
+import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Sentinel;
+import org.springframework.cloud.alibaba.sentinel.feign.SentinelFeign;
+
+/**
+ * @author xiaojing
+ */
+final class FescarSentinelFeignBuilder {
+
+ private FescarSentinelFeignBuilder() {
+ }
+
+ static Feign.Builder builder(BeanFactory beanFactory) {
+ return SentinelFeign.builder().retryer(Retryer.NEVER_RETRY)
+ .client(new FescarFeignClient(beanFactory));
+ }
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixAutoConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixAutoConfiguration.java
new file mode 100644
index 000000000..f7db4b0d9
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixAutoConfiguration.java
@@ -0,0 +1,37 @@
+/*
+ * 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.fescar.feign.hystrix;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.netflix.hystrix.HystrixCommand;
+
+/**
+ * @author xiaojing
+ */
+
+@Configuration
+@ConditionalOnClass(HystrixCommand.class)
+public class FescarHystrixAutoConfiguration {
+
+ @Bean
+ FescarHystrixConcurrencyStrategy fescarHystrixConcurrencyStrategy() {
+ return new FescarHystrixConcurrencyStrategy();
+ }
+
+}
\ No newline at end of file
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixConcurrencyStrategy.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixConcurrencyStrategy.java
new file mode 100644
index 000000000..e21ff1680
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/feign/hystrix/FescarHystrixConcurrencyStrategy.java
@@ -0,0 +1,80 @@
+/*
+ * 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.fescar.feign.hystrix;
+
+import java.util.concurrent.Callable;
+
+import com.alibaba.fescar.core.context.RootContext;
+
+import com.netflix.hystrix.strategy.HystrixPlugins;
+import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
+
+/**
+ * @author xiaojing
+ */
+public class FescarHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {
+
+ private HystrixConcurrencyStrategy delegate;
+
+ public FescarHystrixConcurrencyStrategy() {
+ this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
+ HystrixPlugins.reset();
+ HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
+ }
+
+ @Override
+ public Callable wrapCallable(Callable c) {
+ if (c instanceof FescarContextCallable) {
+ return c;
+ }
+
+ Callable wrappedCallable;
+ if (this.delegate != null) {
+ wrappedCallable = this.delegate.wrapCallable(c);
+ }
+ else {
+ wrappedCallable = c;
+ }
+ if (wrappedCallable instanceof FescarContextCallable) {
+ return wrappedCallable;
+ }
+
+ return new FescarContextCallable<>(wrappedCallable);
+ }
+
+ private static class FescarContextCallable implements Callable {
+
+ private final Callable actual;
+ private final String xid;
+
+ FescarContextCallable(Callable actual) {
+ this.actual = actual;
+ this.xid = RootContext.getXID();
+ }
+
+ @Override
+ public K call() throws Exception {
+ try {
+ RootContext.bind(xid);
+ return actual.call();
+ }
+ finally {
+ RootContext.unbind();
+ }
+ }
+
+ }
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateAutoConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateAutoConfiguration.java
new file mode 100644
index 000000000..91191ed0d
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateAutoConfiguration.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+/*
+ * 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.fescar.rest;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author xiaojing
+ */
+
+@Configuration
+public class FescarRestTemplateAutoConfiguration {
+
+ @Bean
+ public FescarRestTemplateInterceptor fescarRestTemplateInterceptor() {
+ return new FescarRestTemplateInterceptor();
+ }
+
+ @Autowired(required = false)
+ private Collection restTemplates;
+
+ @Autowired
+ private FescarRestTemplateInterceptor fescarRestTemplateInterceptor;
+
+ @PostConstruct
+ public void init() {
+ if (this.restTemplates != null) {
+ for (RestTemplate restTemplate : restTemplates) {
+ List interceptors = new ArrayList(
+ restTemplate.getInterceptors());
+ interceptors.add(this.fescarRestTemplateInterceptor);
+ restTemplate.setInterceptors(interceptors);
+ }
+ }
+ }
+
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateInterceptor.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateInterceptor.java
new file mode 100644
index 000000000..5a5b2a10a
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/rest/FescarRestTemplateInterceptor.java
@@ -0,0 +1,46 @@
+/*
+ * 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.fescar.rest;
+
+import java.io.IOException;
+
+import com.alibaba.fescar.core.context.RootContext;
+
+import org.springframework.http.HttpRequest;
+import org.springframework.http.client.ClientHttpRequestExecution;
+import org.springframework.http.client.ClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.http.client.support.HttpRequestWrapper;
+import org.springframework.util.StringUtils;
+
+/**
+ * @author xiaojing
+ */
+public class FescarRestTemplateInterceptor implements ClientHttpRequestInterceptor {
+ @Override
+ public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] bytes,
+ ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
+ HttpRequestWrapper requestWrapper = new HttpRequestWrapper(httpRequest);
+
+ String xid = RootContext.getXID();
+
+ if (!StringUtils.isEmpty(xid)) {
+ requestWrapper.getHeaders().add(RootContext.KEY_XID, xid);
+ }
+ return clientHttpRequestExecution.execute(requestWrapper, bytes);
+ }
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptor.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptor.java
new file mode 100644
index 000000000..84ffee8e8
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptor.java
@@ -0,0 +1,85 @@
+/*
+ * 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.fescar.web;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.alibaba.fescar.core.context.RootContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+/**
+ * @author xiaojing
+ *
+ * Fescar HandlerInterceptor, Convert Fescar information into
+ * @see com.alibaba.fescar.core.context.RootContext from http request's header in
+ * {@link org.springframework.web.servlet.HandlerInterceptor#preHandle(HttpServletRequest , HttpServletResponse , Object )},
+ * And clean up Fescar information after servlet method invocation in
+ * {@link org.springframework.web.servlet.HandlerInterceptor#afterCompletion(HttpServletRequest, HttpServletResponse, Object, Exception)}
+ */
+public class FescarHandlerInterceptor implements HandlerInterceptor {
+
+ private static final Logger log = LoggerFactory
+ .getLogger(FescarHandlerInterceptor.class);
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
+ Object handler) throws Exception {
+
+ String xid = RootContext.getXID();
+ String rpcXid = request.getHeader(RootContext.KEY_XID);
+ if (log.isDebugEnabled()) {
+ log.debug("xid in RootContext {} xid in RpcContext {}", xid, rpcXid);
+ }
+
+ if (xid == null && rpcXid != null) {
+ RootContext.bind(rpcXid);
+ if (log.isDebugEnabled()) {
+ log.debug("bind {} to RootContext", rpcXid);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
+ Object handler, Exception e) throws Exception {
+
+ String rpcXid = request.getHeader(RootContext.KEY_XID);
+
+ if (StringUtils.isEmpty(rpcXid)) {
+ return;
+ }
+
+ String unbindXid = RootContext.unbind();
+ if (log.isDebugEnabled()) {
+ log.debug("unbind {} from RootContext", unbindXid);
+ }
+ if (!rpcXid.equalsIgnoreCase(unbindXid)) {
+ log.warn("xid in change during RPC from {} to {}", rpcXid, unbindXid);
+ if (unbindXid != null) {
+ RootContext.bind(unbindXid);
+ log.warn("bind {} back to RootContext", unbindXid);
+ }
+ }
+ }
+
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptorConfiguration.java b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptorConfiguration.java
new file mode 100644
index 000000000..c510b1ac7
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptorConfiguration.java
@@ -0,0 +1,31 @@
+/*
+ * 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.fescar.web;
+
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @author xiaojing
+ */
+public class FescarHandlerInterceptorConfiguration implements WebMvcConfigurer {
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(new FescarHandlerInterceptor()).addPathPatterns("/**");
+ }
+}
diff --git a/spring-cloud-alibaba-fescar/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-fescar/src/main/resources/META-INF/spring.factories
new file mode 100644
index 000000000..3560bcee4
--- /dev/null
+++ b/spring-cloud-alibaba-fescar/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,7 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.springframework.cloud.alibaba.fescar.rest.FescarRestTemplateAutoConfiguration,\
+org.springframework.cloud.alibaba.fescar.web.FescarHandlerInterceptorConfiguration,\
+org.springframework.cloud.alibaba.fescar.GlobalTransactionAutoConfiguration,\
+org.springframework.cloud.alibaba.fescar.feign.FescarFeignClientAutoConfiguration,\
+org.springframework.cloud.alibaba.fescar.feign.hystrix.FescarHystrixAutoConfiguration
+
diff --git a/spring-cloud-starter-alibaba/pom.xml b/spring-cloud-starter-alibaba/pom.xml
index 3c91f8d7c..c0de36447 100644
--- a/spring-cloud-starter-alibaba/pom.xml
+++ b/spring-cloud-starter-alibaba/pom.xml
@@ -16,6 +16,7 @@
spring-cloud-starter-alibaba-nacos-config-server
spring-cloud-starter-alibaba-nacos-discovery
spring-cloud-starter-alibaba-sentinel
+ spring-cloud-starter-alibaba-fescar
spring-cloud-starter-stream-rocketmq
spring-cloud-starter-bus-rocketmq
diff --git a/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-fescar/pom.xml b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-fescar/pom.xml
new file mode 100644
index 000000000..8376bfc13
--- /dev/null
+++ b/spring-cloud-starter-alibaba/spring-cloud-starter-alibaba-fescar/pom.xml
@@ -0,0 +1,20 @@
+
+ 4.0.0
+
+
+ org.springframework.cloud
+ spring-cloud-starter-alibaba
+ 0.2.2.BUILD-SNAPSHOT
+
+ spring-cloud-starter-alibaba-fescar
+ Spring Cloud Starter Alibaba Fescar
+
+
+
+ org.springframework.cloud
+ spring-cloud-alibaba-fescar
+
+
+
+