Repository: alibaba/fescar
Pull request #632 (2019-03-19 15:48:08)

fix eureka subscribe role not inited on lookup method
…ecoupling register and lookup

<!-- Please make sure you have read and understood the contributing guidelines -->

### Ⅰ. Describe what this PR did

fix: for eureka register ;if not register,lookup will be error
### Ⅱ. Does this pull request fix one issue?
<!-- If that, add "fixes #xxx" below in the next line, for example, fixes #97. -->


### Ⅲ. Why don't you add test cases (unit test/integration test)? 


### Ⅳ. Describe how to verify it


### Ⅴ. Special notes for reviews



vikenlove: ![图片](https://user-images.githubusercontent.com/2834207/54657420-56d0fd00-4b04-11e9-93f4-f8a0ed75f919.png)

经过测试 已经可以 fescar-discover  client 可以连接注册到eureka 上，但是 却无法连接到 fescar server ，

通过将RP代码 本地跟进后发现 
![图片](https://user-images.githubusercontent.com/2834207/54657532-c47d2900-4b04-11e9-98e3-2fb7e4753961.png)
{DEFAULT=[/172.18.2.244:8091], SERVICE-CONSUMER=[/169.254.23.227:9090]}
{DEFAULT=[/172.18.2.244:8091], SERVICE-CONSUMER=[/169.254.23.227:9090]}

DEFAULT IP 为实际本机的物理IP，但是我们文件中配置的确实127.0.0.1：8091 的fescar-server。同理 SERVICE-CONSUMER 是 我当前 一个服务器调用，在eureka 上的 IP 均为localhost:9090 ，所以是否无法连接到服务 是因为 此处 cluster_address_map  这个MAP 中IP 问题？有待跟进


Patch:
diff --git a/README.md b/README.md
index b6133fb03..121f15ef7 100644
--- a/README.md
+++ b/README.md
@@ -65,7 +65,7 @@ For more details about principle and design, please go to [Fescar wiki page](htt
 
 ## Maven dependency
 ```xml
-<fescar.version>0.3.0</fescar.version>
+<fescar.version>0.4.0</fescar.version>
 
 <dependency>
     <groupId>com.alibaba.fescar</groupId>
diff --git a/common/pom.xml b/common/pom.xml
index f8989a200..4cd902ef9 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-common</artifactId>
diff --git a/config/pom.xml b/config/pom.xml
index a7356d8ed..b78dbf713 100644
--- a/config/pom.xml
+++ b/config/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-config</artifactId>
diff --git a/core/pom.xml b/core/pom.xml
index 237f0684e..1364cd1ad 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-core</artifactId>
diff --git a/core/src/main/java/com/alibaba/fescar/core/service/ConfigurationKeys.java b/core/src/main/java/com/alibaba/fescar/core/constants/ConfigurationKeys.java
similarity index 96%
rename from core/src/main/java/com/alibaba/fescar/core/service/ConfigurationKeys.java
rename to core/src/main/java/com/alibaba/fescar/core/constants/ConfigurationKeys.java
index 3bd67d29b..7fb884fc5 100644
--- a/core/src/main/java/com/alibaba/fescar/core/service/ConfigurationKeys.java
+++ b/core/src/main/java/com/alibaba/fescar/core/constants/ConfigurationKeys.java
@@ -14,10 +14,12 @@
  *  limitations under the License.
  */
 
-package com.alibaba.fescar.core.service;
+package com.alibaba.fescar.core.constants;
 
 /**
  * The type Configuration keys.
+ *
+ * @author jimin.jm @alibaba-inc.com
  */
 public class ConfigurationKeys {
 
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java b/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java
index 2bfc4c7d1..de6b57431 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java
@@ -33,7 +33,7 @@ public class Version {
     /**
      * The constant CURRENT.
      */
-    public static final String CURRENT = "0.4.0";
+    public static final String CURRENT = "0.4.1";
 
     /**
      * The constant VERSION_MAP.
diff --git a/core/src/main/java/com/alibaba/fescar/core/rpc/ClientType.java b/core/src/main/java/com/alibaba/fescar/core/rpc/ClientType.java
index c7de72c70..271d5e0bf 100644
--- a/core/src/main/java/com/alibaba/fescar/core/rpc/ClientType.java
+++ b/core/src/main/java/com/alibaba/fescar/core/rpc/ClientType.java
@@ -18,6 +18,8 @@ package com.alibaba.fescar.core.rpc;
 
 /**
  * The enum Client type.
+ *
+ * @author jimin.jm @alibaba-inc.com
  */
 public enum ClientType {
 
diff --git a/core/src/main/java/com/alibaba/fescar/core/rpc/TransactionMessageHandler.java b/core/src/main/java/com/alibaba/fescar/core/rpc/TransactionMessageHandler.java
index aee3d18e8..3e2d2e925 100644
--- a/core/src/main/java/com/alibaba/fescar/core/rpc/TransactionMessageHandler.java
+++ b/core/src/main/java/com/alibaba/fescar/core/rpc/TransactionMessageHandler.java
@@ -21,6 +21,8 @@ import com.alibaba.fescar.core.protocol.AbstractResultMessage;
 
 /**
  * To handle the received RPC message on upper level.
+ *
+ * @author jimin.jm @alibaba-inc.com
  */
 public interface TransactionMessageHandler {
 
diff --git a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/AbstractRpcRemotingClient.java b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/AbstractRpcRemotingClient.java
index ed86009b8..265e90588 100644
--- a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/AbstractRpcRemotingClient.java
+++ b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/AbstractRpcRemotingClient.java
@@ -38,8 +38,6 @@ import com.alibaba.fescar.core.rpc.ClientMessageListener;
 import com.alibaba.fescar.core.rpc.ClientMessageSender;
 import com.alibaba.fescar.core.rpc.RemotingService;
 import com.alibaba.fescar.core.rpc.netty.NettyPoolKey.TransactionRole;
-import com.alibaba.fescar.core.service.ServiceManager;
-import com.alibaba.fescar.core.service.ServiceManagerStaticConfigImpl;
 import com.alibaba.fescar.discovery.registry.RegistryFactory;
 import com.alibaba.nacos.client.naming.utils.CollectionUtils;
 
@@ -90,10 +88,6 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
     private static final int MAX_MERGE_SEND_MILLS = 1;
     private static final String THREAD_PREFIX_SPLIT_CHAR = "_";
 
-    /**
-     * The Service manager.
-     */
-    protected ServiceManager serviceManager;
 
     /**
      * The Netty client key pool.
@@ -142,7 +136,6 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
         NettyPoolableFactory keyPoolableFactory = new NettyPoolableFactory(this);
         nettyClientKeyPool = new GenericKeyedObjectPool(keyPoolableFactory);
         nettyClientKeyPool.setConfig(getNettyPoolConfig());
-        serviceManager = new ServiceManagerStaticConfigImpl();
         super.init();
     }
 
@@ -259,7 +252,7 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
             }
             super.destroy();
         } catch (Exception exx) {
-            LOGGER.error("shutdown error:" + exx.getMessage());
+            LOGGER.error("Failed to shutdown: {}", exx.getMessage());
         }
     }
 
@@ -269,7 +262,7 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
             RpcMessage rpcMessage = (RpcMessage)msg;
             if (rpcMessage.getBody() == HeartbeatMessage.PONG) {
                 if (LOGGER.isDebugEnabled()) {
-                    LOGGER.debug("received PONG from " + ctx.channel().remoteAddress());
+                    LOGGER.debug("received PONG from {}", ctx.channel().remoteAddress());
                 }
                 return;
             }
@@ -284,7 +277,7 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
                 MessageFuture future = futures.remove(msgId);
                 if (future == null) {
                     if (LOGGER.isInfoEnabled()) {
-                        LOGGER.info("msg:" + msgId + " is not found in futures.");
+                        LOGGER.info("msg: {} is not found in futures.", msgId);
                     }
                 } else {
                     future.setResultMessage(results.getMsgs()[i]);
@@ -295,6 +288,18 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
         super.channelRead(ctx, msg);
     }
 
+    @Override
+    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+        if (messageExecutor.isShutdown()) {
+            return;
+        }
+        if (LOGGER.isInfoEnabled()) {
+            LOGGER.info("channel inactive: {}", ctx.channel());
+        }
+        releaseChannel(ctx.channel(), NetUtil.toStringAddress(ctx.channel().remoteAddress()));
+        super.channelInactive(ctx);
+    }
+
     /**
      * Gets client message listener.
      *
@@ -321,6 +326,27 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
         }
     }
 
+    protected void reconnect(String transactionServiceGroup) {
+        List<String> availList = null;
+        try {
+            availList = getAvailServerList(transactionServiceGroup);
+        } catch (Exception exx) {
+            LOGGER.error("Failed to get available servers: {}" + exx.getMessage());
+        }
+        if (CollectionUtils.isEmpty(availList)) {
+            LOGGER.error("no available server to connect.");
+            return;
+        }
+        for (String serverAddress : availList) {
+            try {
+                connect(serverAddress);
+            } catch (Exception e) {
+                LOGGER.error(FrameworkErrorCode.NetConnect.errCode,
+                        "can not connect to " + serverAddress + " cause:" + e.getMessage(), e);
+            }
+        }
+    }
+
     /**
      * Gets avail server list.
      *
@@ -358,6 +384,14 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
      */
     protected abstract Channel connect(String serverAddress);
 
+    /**
+     * Release channel.
+     *
+     * @param channel       the channel
+     * @param serverAddress the server address
+     */
+    protected abstract void releaseChannel(Channel channel, String serverAddress);
+
     /**
      * Gets netty pool config.
      *
diff --git a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/NettyClientConfig.java b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/NettyClientConfig.java
index 70714e0bd..1c3cf2518 100644
--- a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/NettyClientConfig.java
+++ b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/NettyClientConfig.java
@@ -22,6 +22,8 @@ import io.netty.channel.Channel;
 
 /**
  * The type Netty client config.
+ *
+ * @author jimin.jm @alibaba-inc.com
  */
 public class NettyClientConfig extends NettyBaseConfig {
 
diff --git a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/RmRpcClient.java b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/RmRpcClient.java
index f572db624..e540c9ea4 100644
--- a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/RmRpcClient.java
+++ b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/RmRpcClient.java
@@ -16,7 +16,6 @@
 
 package com.alibaba.fescar.core.rpc.netty;
 
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -41,7 +40,6 @@ import com.alibaba.fescar.core.protocol.HeartbeatMessage;
 import com.alibaba.fescar.core.protocol.RegisterRMRequest;
 import com.alibaba.fescar.core.protocol.RegisterRMResponse;
 import com.alibaba.fescar.core.rpc.netty.NettyPoolKey.TransactionRole;
-import com.alibaba.nacos.client.naming.utils.CollectionUtils;
 
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandler.Sharable;
@@ -149,7 +147,7 @@ public final class RmRpcClient extends AbstractRpcRemotingClient {
             timerExecutor.scheduleAtFixedRate(new Runnable() {
                 @Override
                 public void run() {
-                    reconnect();
+                    reconnect(transactionServiceGroup);
                 }
             }, SCHEDULE_INTERVAL_MILLS, SCHEDULE_INTERVAL_MILLS, TimeUnit.SECONDS);
             ExecutorService mergeSendExecutorService = new ThreadPoolExecutor(MAX_MERGE_SEND_THREAD,
@@ -196,39 +194,6 @@ public final class RmRpcClient extends AbstractRpcRemotingClient {
         return TransactionRole.RMROLE;
     }
 
-    private void reconnect() {
-        List<String> availList = null;
-        try {
-            availList = getAvailServerList(transactionServiceGroup);
-        } catch (Exception exx) {
-            LOGGER.error(exx.getMessage());
-        }
-        if (CollectionUtils.isEmpty(availList)) {
-            LOGGER.error("no available server to connect.");
-            return;
-        }
-        for (String serverAddress : availList) {
-            try {
-                connect(serverAddress);
-            } catch (Exception e) {
-                LOGGER.error(FrameworkErrorCode.NetConnect.errCode,
-                    "can not connect to " + serverAddress + " cause:" + e.getMessage(), e);
-            }
-        }
-    }
-
-    @Override
-    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-        if (messageExecutor.isShutdown()) {
-            return;
-        }
-        if (LOGGER.isInfoEnabled()) {
-            LOGGER.info("channel inactive:" + ctx.channel());
-        }
-        releaseChannel(ctx.channel(), NetUtil.toStringAddress(ctx.channel().remoteAddress()));
-        super.channelInactive(ctx);
-    }
-
     @Override
     public Object sendMsgWithResponse(Object msg, long timeout) throws TimeoutException {
         return super.sendAsyncRequestWithResponse(XID.getServerAddress(RootContext.getXID()),
@@ -281,13 +246,8 @@ public final class RmRpcClient extends AbstractRpcRemotingClient {
         }
     }
 
-    /**
-     * Release channel.
-     *
-     * @param channel       the channel
-     * @param serverAddress the server address
-     */
-    public void releaseChannel(Channel channel, String serverAddress) {
+    @Override
+    protected void releaseChannel(Channel channel, String serverAddress) {
         if (null == channel || null == serverAddress) { return; }
         Object connectLock = channelLocks.get(serverAddress);
         try {
diff --git a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/TmRpcClient.java b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/TmRpcClient.java
index 610582fed..cb1efff35 100644
--- a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/TmRpcClient.java
+++ b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/TmRpcClient.java
@@ -35,6 +35,7 @@ import com.alibaba.fescar.common.thread.RejectedPolicies;
 import com.alibaba.fescar.common.util.NetUtil;
 import com.alibaba.fescar.config.Configuration;
 import com.alibaba.fescar.config.ConfigurationFactory;
+import com.alibaba.fescar.core.constants.ConfigurationKeys;
 import com.alibaba.fescar.core.context.RootContext;
 import com.alibaba.fescar.core.protocol.AbstractMessage;
 import com.alibaba.fescar.core.protocol.HeartbeatMessage;
@@ -43,7 +44,6 @@ import com.alibaba.fescar.core.protocol.RegisterTMResponse;
 import com.alibaba.fescar.core.protocol.ResultCode;
 import com.alibaba.fescar.core.protocol.transaction.GlobalBeginResponse;
 import com.alibaba.fescar.core.rpc.netty.NettyPoolKey.TransactionRole;
-import com.alibaba.fescar.core.service.ConfigurationKeys;
 import com.alibaba.fescar.discovery.loadbalance.LoadBalanceFactory;
 import com.alibaba.fescar.discovery.registry.RegistryFactory;
 import com.alibaba.nacos.client.naming.utils.CollectionUtils;
@@ -162,7 +162,7 @@ public final class TmRpcClient extends AbstractRpcRemotingClient {
             @Override
             public void run() {
                 try {
-                    reconnect();
+                    reconnect(transactionServiceGroup);
                 } catch (Exception ignore) {
                     LOGGER.error(ignore.getMessage());
                 }
@@ -170,39 +170,6 @@ public final class TmRpcClient extends AbstractRpcRemotingClient {
         }, healthCheckDelay, healthCheckPeriod, TimeUnit.SECONDS);
     }
 
-    private void reconnect() {
-        List<String> availList = null;
-        try {
-            availList = getAvailServerList(transactionServiceGroup);
-        } catch (Exception exx) {
-            LOGGER.error(exx.getMessage());
-        }
-        if (CollectionUtils.isEmpty(availList)) {
-            LOGGER.error("no available server to connect.");
-            return;
-        }
-        for (String serverAddress : availList) {
-            try {
-                connect(serverAddress);
-            } catch (Exception e) {
-                LOGGER.error(FrameworkErrorCode.NetConnect.errCode,
-                    "can not connect to " + serverAddress + " cause:" + e.getMessage(), e);
-            }
-        }
-    }
-
-    @Override
-    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-        if (messageExecutor.isShutdown()) {
-            return;
-        }
-        if (LOGGER.isInfoEnabled()) {
-            LOGGER.info("channel inactive:" + ctx.channel());
-        }
-        releaseChannel(ctx.channel(), NetUtil.toStringAddress(ctx.channel().remoteAddress()));
-        super.channelInactive(ctx);
-    }
-
     @Override
     public Object sendMsgWithResponse(Object msg, long timeout) throws TimeoutException {
         String svrAddr = XID.getServerAddress(RootContext.getXID());
@@ -210,7 +177,7 @@ public final class TmRpcClient extends AbstractRpcRemotingClient {
         Channel acquireChannel = connect(validAddress);
         Object result = super.sendAsyncRequestWithResponse(validAddress, acquireChannel, msg, timeout);
         if (result instanceof GlobalBeginResponse
-            && ((GlobalBeginResponse)result).getResultCode() == ResultCode.Failed) {
+                && ((GlobalBeginResponse) result).getResultCode() == ResultCode.Failed) {
             LOGGER.error("begin response error,release channel:" + acquireChannel);
             releaseChannel(acquireChannel, validAddress);
         }
@@ -273,14 +240,11 @@ public final class TmRpcClient extends AbstractRpcRemotingClient {
 
     }
 
-    /**
-     * Release channel.
-     *
-     * @param channel       the channel
-     * @param serverAddress the server address
-     */
-    public void releaseChannel(Channel channel, String serverAddress) {
-        if (null == channel || null == serverAddress) { return; }
+    @Override
+    protected void releaseChannel(Channel channel, String serverAddress) {
+        if (null == channel || null == serverAddress) {
+            return;
+        }
         try {
             Object connectLock = channelLocks.get(serverAddress);
             synchronized (connectLock) {
@@ -303,12 +267,6 @@ public final class TmRpcClient extends AbstractRpcRemotingClient {
         }
     }
 
-    /**
-     * Connect channel.
-     *
-     * @param serverAddress the server address
-     * @return the channel
-     */
     @Override
     protected Channel connect(String serverAddress) {
         Channel channelToServer = channels.get(serverAddress);
diff --git a/core/src/main/java/com/alibaba/fescar/core/service/AddressWatcher.java b/core/src/main/java/com/alibaba/fescar/core/service/AddressWatcher.java
deleted file mode 100644
index 245ceb3d9..000000000
--- a/core/src/main/java/com/alibaba/fescar/core/service/AddressWatcher.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *  Copyright 1999-2018 Alibaba Group Holding Ltd.
- *
- *  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 com.alibaba.fescar.core.service;
-
-/**
- * Watch for server address list change
- */
-public interface AddressWatcher {
-
-    /**
-     * On change.
-     *
-     * @param serverAddressArray the server address array
-     */
-    void onChange(String[] serverAddressArray);
-}
diff --git a/core/src/main/java/com/alibaba/fescar/core/service/ServiceManager.java b/core/src/main/java/com/alibaba/fescar/core/service/ServiceManager.java
deleted file mode 100644
index ef316ccca..000000000
--- a/core/src/main/java/com/alibaba/fescar/core/service/ServiceManager.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *  Copyright 1999-2018 Alibaba Group Holding Ltd.
- *
- *  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 com.alibaba.fescar.core.service;
-
-/**
- * Service Registry and Discovery
- */
-public interface ServiceManager {
-
-    /**
-     * Register address to txServiceGroup server list.
-     *
-     * @param txServiceGroup transaction service group (service name)
-     * @param address        server node address
-     */
-    void register(String txServiceGroup, String address);
-
-    /**
-     * Unregister address to txServiceGroup server list.
-     *
-     * @param txServiceGroup transaction service group (service name)
-     * @param address        server node address
-     */
-    void unregister(String txServiceGroup, String address);
-
-    /**
-     * Watch service addresses for the give txServiceGroup
-     *
-     * @param txServiceGroup transaction service group (service name)
-     * @param watcher        service address watcher
-     */
-    void watch(String txServiceGroup, AddressWatcher watcher);
-
-    /**
-     * Lookup server addresses for the given txServiceGroup
-     *
-     * @param txServiceGroup transaction service group (service name)
-     * @return available addresses
-     */
-    String[] lookup(String txServiceGroup);
-}
diff --git a/core/src/main/java/com/alibaba/fescar/core/service/ServiceManagerStaticConfigImpl.java b/core/src/main/java/com/alibaba/fescar/core/service/ServiceManagerStaticConfigImpl.java
deleted file mode 100644
index 45b638152..000000000
--- a/core/src/main/java/com/alibaba/fescar/core/service/ServiceManagerStaticConfigImpl.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- *  Copyright 1999-2018 Alibaba Group Holding Ltd.
- *
- *  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 com.alibaba.fescar.core.service;
-
-import com.alibaba.fescar.common.exception.FrameworkException;
-import com.alibaba.fescar.common.exception.NotSupportYetException;
-import com.alibaba.fescar.common.util.StringUtils;
-import com.alibaba.fescar.config.Configuration;
-import com.alibaba.fescar.config.ConfigurationFactory;
-
-import static com.alibaba.fescar.common.exception.FrameworkErrorCode.InvalidConfiguration;
-import static com.alibaba.fescar.core.service.ConfigurationKeys.SERVER_NODE_SPLIT_CHAR;
-
-/**
- * The type Service manager static config.
- */
-public class ServiceManagerStaticConfigImpl implements ServiceManager {
-
-    private Configuration configuration = ConfigurationFactory.getInstance();
-
-    @Override
-    public void register(String txServiceGroup, String address) {
-        throw new NotSupportYetException("Dynamic registry");
-
-    }
-
-    @Override
-    public void unregister(String txServiceGroup, String address) {
-        throw new NotSupportYetException("Dynamic un-registry");
-
-    }
-
-    @Override
-    public void watch(String txServiceGroup, AddressWatcher watcher) {
-        throw new NotSupportYetException("Watch");
-
-    }
-
-    private String[] serverAddresses = null;
-
-    @Override
-    public String[] lookup(String txServiceGroup) {
-        if (serverAddresses != null) {
-            return serverAddresses;
-        }
-        String rGroup = configuration.getConfig(ConfigurationKeys.SERVICE_GROUP_MAPPING_PREFIX + txServiceGroup);
-        if (rGroup == null) {
-            throw new FrameworkException(InvalidConfiguration);
-        }
-        String rGroupDataId = ConfigurationKeys.SERVICE_PREFIX + rGroup + ConfigurationKeys.GROUPLIST_POSTFIX;
-        String serverListConfig = configuration.getConfig(rGroupDataId);
-        if (StringUtils.isNullOrEmpty(serverListConfig)) {
-            throw new FrameworkException(InvalidConfiguration);
-        }
-        serverAddresses = serverListConfig.split(SERVER_NODE_SPLIT_CHAR);
-        if (serverAddresses == null || serverAddresses.length == 0) {
-            throw new FrameworkException(InvalidConfiguration);
-        }
-        return serverAddresses;
-
-    }
-}
diff --git a/discovery/pom.xml b/discovery/pom.xml
index e7b715df0..81903069d 100644
--- a/discovery/pom.xml
+++ b/discovery/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <packaging>jar</packaging>
diff --git a/discovery/src/main/java/com/alibaba/fescar/discovery/registry/EurekaRegistryServiceImpl.java b/discovery/src/main/java/com/alibaba/fescar/discovery/registry/EurekaRegistryServiceImpl.java
index b4fb24c6b..ed72bd31b 100644
--- a/discovery/src/main/java/com/alibaba/fescar/discovery/registry/EurekaRegistryServiceImpl.java
+++ b/discovery/src/main/java/com/alibaba/fescar/discovery/registry/EurekaRegistryServiceImpl.java
@@ -22,12 +22,10 @@ import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-
 import com.alibaba.fescar.common.exception.EurekaRegistryException;
 import com.alibaba.fescar.common.util.NetUtil;
 import com.alibaba.fescar.config.Configuration;
 import com.alibaba.fescar.config.ConfigurationFactory;
-
 import com.google.common.collect.Lists;
 import com.netflix.appinfo.ApplicationInfoManager;
 import com.netflix.appinfo.InstanceInfo;
@@ -41,6 +39,8 @@ import com.netflix.discovery.EurekaEventListener;
 import com.netflix.discovery.shared.Application;
 import com.netflix.discovery.shared.Applications;
 import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * The type Eureka registry service.
@@ -49,6 +49,7 @@ import org.apache.commons.lang3.StringUtils;
  * @date: 2018/3/6
  */
 public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventListener> {
+    private static final Logger LOGGER = LoggerFactory.getLogger(EurekaRegistryServiceImpl.class);
 
     private static final String DEFAULT_APPLICATION = "default";
     private static final String PRO_SERVICE_URL_KEY = "serviceUrl";
@@ -59,6 +60,7 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
     private static final String REGISTRY_WEIGHT = "weight";
     private static final String EUREKA_CONFIG_SERVER_URL_KEY = "eureka.serviceUrl.default";
     private static final String EUREKA_CONFIG_REFRESH_KEY = "eureka.client.refresh.interval";
+    private static final String EUREKA_CONFIG_SHOULD_REGISTER = "eureka.registration.enabled";
     private static final String EUREKA_CONFIG_METADATA_WEIGHT = "eureka.metadata.weight";
     private static final int EUREKA_REFRESH_INTERVAL = 5;
     private static final String DEFAULT_WEIGHT = "1";
@@ -95,7 +97,7 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
             instanceConfig.setApplicationName(getApplicationName());
             instanceConfig.setInstanceId(getInstanceId());
         }
-        getEurekaClient();
+        getEurekaClient(true);
         applicationInfoManager.setInstanceStatus(InstanceInfo.InstanceStatus.UP);
     }
 
@@ -111,16 +113,14 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
 
     @Override
     public void subscribe(String cluster, EurekaEventListener listener) throws Exception {
-        assertEureka();
         subscribeListener = true;
-        eurekaClient.registerEventListener(listener);
+        getEurekaClient(false).registerEventListener(listener);
     }
 
     @Override
     public void unsubscribe(String cluster, EurekaEventListener listener) throws Exception {
-        assertEureka();
         subscribeListener = false;
-        eurekaClient.unregisterEventListener(listener);
+        getEurekaClient(false).unregisterEventListener(listener);
     }
 
     @Override
@@ -131,14 +131,16 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
             return null;
         }
 
-        assertEureka();
-
         if (!subscribeListener) {
             refreshCluster();
             subscribe(null, new EurekaEventListener() {
                 @Override
                 public void onEvent(EurekaEvent event) {
-                    refreshCluster();
+                    try {
+                        refreshCluster();
+                    } catch (Exception e) {
+                        LOGGER.error("Eureka event listener refreshCluster error!");
+                    }
                 }
             });
         }
@@ -146,8 +148,8 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
         return Lists.newArrayList(CLUSTER_ADDRESS_MAP.get(clusterName.toUpperCase()));
     }
 
-    private static void refreshCluster() {
-        Applications applications = eurekaClient.getApplications();
+    private static void refreshCluster() throws EurekaRegistryException{
+        Applications applications = getEurekaClient(false).getApplications();
         List<Application> list = applications.getRegisteredApplications();
         if (list == null || list.isEmpty()) {
             CLUSTER_ADDRESS_MAP.clear();
@@ -172,7 +174,7 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
         eurekaClient = null;
     }
 
-    private static Properties getEurekaProperties() {
+    private static Properties getEurekaProperties(boolean needRegister) {
         Properties eurekaProperties = new Properties();
         eurekaProperties.setProperty(EUREKA_CONFIG_REFRESH_KEY, String.valueOf(EUREKA_REFRESH_INTERVAL));
 
@@ -189,6 +191,10 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
             eurekaProperties.setProperty(EUREKA_CONFIG_METADATA_WEIGHT, DEFAULT_WEIGHT);
         }
 
+        if (!needRegister) {
+            eurekaProperties.setProperty(EUREKA_CONFIG_SHOULD_REGISTER, "false");
+        }
+
         return eurekaProperties;
     }
 
@@ -200,16 +206,20 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
         return application;
     }
 
-    private static EurekaClient getEurekaClient() throws Exception {
+    private static EurekaClient getEurekaClient(boolean needRegister) throws EurekaRegistryException{
         if (eurekaClient == null) {
             synchronized (EurekaRegistryServiceImpl.class) {
                 try {
-                    if (eurekaClient == null) {
-                        ConfigurationManager.loadProperties(getEurekaProperties());
-                        InstanceInfo instanceInfo = new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get();
-                        applicationInfoManager = new ApplicationInfoManager(instanceConfig, instanceInfo);
-                        eurekaClient = new DiscoveryClient(applicationInfoManager, new DefaultEurekaClientConfig());
+                    if (eurekaClient != null) {
+                        return eurekaClient;
                     }
+                    if (!needRegister){
+                        instanceConfig = new CustomEurekaInstanceConfig();
+                    }
+                    ConfigurationManager.loadProperties(getEurekaProperties(needRegister));
+                    InstanceInfo instanceInfo = new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get();
+                    applicationInfoManager = new ApplicationInfoManager(instanceConfig, instanceInfo);
+                    eurekaClient = new DiscoveryClient(applicationInfoManager, new DefaultEurekaClientConfig());
                 } catch (Exception e) {
                     close();
                     throw new EurekaRegistryException("register eureka is error!", e);
@@ -219,12 +229,6 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
         return eurekaClient;
     }
 
-    private static void assertEureka() {
-        if (eurekaClient == null) {
-            throw new EurekaRegistryException("eureka client is not register,do this operation had to be register!");
-        }
-    }
-
     private static String getInstanceId() {
         return String.format("%s:%s:%d", instanceConfig.getAppname(), instanceConfig.getIpAddress(),
             instanceConfig.getNonSecurePort());
diff --git a/distribution/pom.xml b/distribution/pom.xml
index 1f68d0432..9c6759877 100644
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-distribution</artifactId>
diff --git a/dubbo-alibaba/pom.xml b/dubbo-alibaba/pom.xml
index eec324ed8..c15ec241f 100644
--- a/dubbo-alibaba/pom.xml
+++ b/dubbo-alibaba/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/dubbo/pom.xml b/dubbo/pom.xml
index 0cc8f7ce3..e5299e739 100644
--- a/dubbo/pom.xml
+++ b/dubbo/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-dubbo</artifactId>
diff --git a/pom.xml b/pom.xml
index 93b88cf1c..1c2a01e30 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
 
     <groupId>com.alibaba.fescar</groupId>
     <artifactId>fescar-all</artifactId>
-    <version>0.4.0</version>
+    <version>0.4.1-SNAPSHOT</version>
     <modules>
         <module>config</module>
         <module>common</module>
diff --git a/rm-datasource/pom.xml b/rm-datasource/pom.xml
index 8dc2f47d7..017756a63 100644
--- a/rm-datasource/pom.xml
+++ b/rm-datasource/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-rm-datasource</artifactId>
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/AsyncWorker.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/AsyncWorker.java
index d94e77285..00702a8c5 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/AsyncWorker.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/AsyncWorker.java
@@ -40,7 +40,7 @@ import com.alibaba.fescar.rm.datasource.undo.UndoLogManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static com.alibaba.fescar.core.service.ConfigurationKeys.CLIENT_ASYNC_COMMIT_BUFFER_LIMIT;
+import static com.alibaba.fescar.core.constants.ConfigurationKeys.CLIENT_ASYNC_COMMIT_BUFFER_LIMIT;
 
 /**
  * The type Async worker.
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/DeleteExecutor.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/DeleteExecutor.java
index 99eeba870..fbbce1244 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/DeleteExecutor.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/DeleteExecutor.java
@@ -23,6 +23,7 @@ import java.sql.Statement;
 import java.util.ArrayList;
 import java.util.List;
 
+import com.alibaba.druid.util.JdbcConstants;
 import com.alibaba.fescar.rm.datasource.ParametersHolder;
 import com.alibaba.fescar.rm.datasource.StatementProxy;
 import com.alibaba.fescar.rm.datasource.sql.SQLDeleteRecognizer;
@@ -30,6 +31,8 @@ import com.alibaba.fescar.rm.datasource.sql.SQLRecognizer;
 import com.alibaba.fescar.rm.datasource.sql.struct.TableMeta;
 import com.alibaba.fescar.rm.datasource.sql.struct.TableRecords;
 
+import com.alibaba.fescar.rm.datasource.undo.KeywordChecker;
+import com.alibaba.fescar.rm.datasource.undo.KeywordCheckerFactory;
 import org.apache.commons.lang.StringUtils;
 
 /**
@@ -54,12 +57,13 @@ public class DeleteExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
 
     @Override
     protected TableRecords beforeImage() throws SQLException {
-        SQLDeleteRecognizer visitor = (SQLDeleteRecognizer)sqlRecognizer;
+        SQLDeleteRecognizer visitor = (SQLDeleteRecognizer) sqlRecognizer;
+        KeywordChecker keywordChecker = KeywordCheckerFactory.getKeywordChecker(JdbcConstants.MYSQL);
 
         TableMeta tmeta = getTableMeta(visitor.getTableName());
         List<String> columns = new ArrayList<>();
         for (String column : tmeta.getAllColumns().keySet()) {
-            columns.add(column);
+            columns.add(keywordChecker.checkAndReplace(column));
         }
 
         StringBuffer selectSQLAppender = new StringBuffer("SELECT ");
@@ -73,11 +77,11 @@ public class DeleteExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
         String whereCondition = null;
         ArrayList<Object> paramAppender = new ArrayList<>();
         if (statementProxy instanceof ParametersHolder) {
-            whereCondition = visitor.getWhereCondition((ParametersHolder)statementProxy, paramAppender);
+            whereCondition = visitor.getWhereCondition((ParametersHolder) statementProxy, paramAppender);
         } else {
             whereCondition = visitor.getWhereCondition();
         }
-        selectSQLAppender.append(" FROM " + getFromTableInSQL());
+        selectSQLAppender.append(" FROM " + keywordChecker.checkAndReplace(getFromTableInSQL()));
         if (StringUtils.isNotBlank(whereCondition)) {
             selectSQLAppender.append(" WHERE " + whereCondition);
         }
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/LockRetryController.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/LockRetryController.java
index cd08d11fc..6dbc6bbfe 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/LockRetryController.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/LockRetryController.java
@@ -17,7 +17,7 @@
 package com.alibaba.fescar.rm.datasource.exec;
 
 import com.alibaba.fescar.config.ConfigurationFactory;
-import com.alibaba.fescar.core.service.ConfigurationKeys;
+import com.alibaba.fescar.core.constants.ConfigurationKeys;
 
 /**
  * The type Lock retry controller.
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/undo/mysql/keyword/MySQLKeywordChecker.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/undo/mysql/keyword/MySQLKeywordChecker.java
index 63ca8db2d..727d84600 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/undo/mysql/keyword/MySQLKeywordChecker.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/undo/mysql/keyword/MySQLKeywordChecker.java
@@ -18,18 +18,22 @@ package com.alibaba.fescar.rm.datasource.undo.mysql.keyword;
 
 import com.alibaba.fescar.rm.datasource.undo.KeywordChecker;
 
-import org.apache.commons.lang3.StringUtils;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * The type My sql keyword checker.
  *
- * @author Wu
- * @date 2019 /3/5 MySQL keyword checker
+ * @author xingfudeshi@gmail.com
+ * @date 2019/3/5 MySQL keyword checker
  */
 public class MySQLKeywordChecker implements KeywordChecker {
-    private static volatile KeywordChecker keywordChecker;
+    private static volatile KeywordChecker keywordChecker = null;
+    private static volatile Set<String> keywordSet = null;
 
-    private MySQLKeywordChecker() {}
+    private MySQLKeywordChecker() {
+    }
 
     /**
      * get instance of type MySQL keyword checker
@@ -41,6 +45,7 @@ public class MySQLKeywordChecker implements KeywordChecker {
             synchronized (MySQLKeywordChecker.class) {
                 if (keywordChecker == null) {
                     keywordChecker = new MySQLKeywordChecker();
+                    keywordSet = Arrays.stream(MySQLKeyword.values()).map(MySQLKeyword::name).collect(Collectors.toSet());
                 }
             }
         }
@@ -524,30 +529,27 @@ public class MySQLKeywordChecker implements KeywordChecker {
          */
         public final String name;
 
-        MySQLKeyword() {
-            this(null);
-        }
-
         MySQLKeyword(String name) {
             this.name = name;
         }
     }
 
+
     @Override
     public boolean check(String fieldOrTableName) {
-        try {
-            if (StringUtils.isNotBlank(fieldOrTableName)) {
-                MySQLKeyword.valueOf(fieldOrTableName.toUpperCase());
-                return true;
-            }
-        } catch (IllegalArgumentException e) {
-            //do nothing
+        if (keywordSet.contains(fieldOrTableName)) {
+            return true;
+        }
+        if (null != fieldOrTableName) {
+            fieldOrTableName = fieldOrTableName.toUpperCase();
         }
-        return false;
+        return keywordSet.contains(fieldOrTableName);
+
     }
 
     @Override
     public String checkAndReplace(String fieldOrTableName) {
         return check(fieldOrTableName) ? "`" + fieldOrTableName + "`" : fieldOrTableName;
     }
+
 }
diff --git a/rm/pom.xml b/rm/pom.xml
index 0a0b90595..e478e7d56 100644
--- a/rm/pom.xml
+++ b/rm/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-rm</artifactId>
diff --git a/server/pom.xml b/server/pom.xml
index 44d217f15..ef18a791d 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-server</artifactId>
diff --git a/server/src/main/java/com/alibaba/fescar/server/session/FileBasedSessionManager.java b/server/src/main/java/com/alibaba/fescar/server/session/FileBasedSessionManager.java
index 76eea6b46..b7f31825f 100644
--- a/server/src/main/java/com/alibaba/fescar/server/session/FileBasedSessionManager.java
+++ b/server/src/main/java/com/alibaba/fescar/server/session/FileBasedSessionManager.java
@@ -24,8 +24,8 @@ import java.util.Map;
 
 import com.alibaba.fescar.common.exception.ShouldNeverHappenException;
 import com.alibaba.fescar.config.ConfigurationFactory;
+import com.alibaba.fescar.core.constants.ConfigurationKeys;
 import com.alibaba.fescar.core.model.GlobalStatus;
-import com.alibaba.fescar.core.service.ConfigurationKeys;
 import com.alibaba.fescar.server.store.FileTransactionStoreManager;
 import com.alibaba.fescar.server.store.SessionStorable;
 import com.alibaba.fescar.server.store.TransactionStoreManager;
diff --git a/spring/pom.xml b/spring/pom.xml
index c19c5455a..85102a852 100644
--- a/spring/pom.xml
+++ b/spring/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-spring</artifactId>
diff --git a/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionalInterceptor.java b/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionalInterceptor.java
index d18053000..5e3b856b0 100644
--- a/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionalInterceptor.java
+++ b/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionalInterceptor.java
@@ -19,6 +19,7 @@ package com.alibaba.fescar.spring.annotation;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.concurrent.Callable;
+import java.util.Arrays;
 
 import com.alibaba.fescar.common.exception.ShouldNeverHappenException;
 import com.alibaba.fescar.common.util.StringUtils;
@@ -140,21 +141,10 @@ public class GlobalTransactionalInterceptor implements MethodInterceptor {
     }
 
     private String formatMethod(Method method) {
-        StringBuilder sb = new StringBuilder();
-
-        String methodName = method.getName();
-        Class<?>[] params = method.getParameterTypes();
-        sb.append(methodName);
-        sb.append("(");
-
-        int paramPos = 0;
-        for (Class<?> clazz : params) {
-            sb.append(clazz.getName());
-            if (++paramPos < params.length) {
-                sb.append(",");
-            }
-        }
-        sb.append(")");
-        return sb.toString();
+        String paramTypes = Arrays.stream(method.getParameterTypes())
+                .map(Class::getName)
+                .reduce((p1, p2) -> String.format("%s, %s", p1, p2))
+                .orElse("");
+        return method.getName() + "(" + paramTypes + ")";
     }
 }
diff --git a/tcc/pom.xml b/tcc/pom.xml
index c7fc5f18d..b71b78604 100644
--- a/tcc/pom.xml
+++ b/tcc/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-tcc</artifactId>
diff --git a/tm/pom.xml b/tm/pom.xml
index a95e9123a..2cdbc8472 100644
--- a/tm/pom.xml
+++ b/tm/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-tm</artifactId>


Test patch:
diff --git a/config/src/test/java/com/alibaba/fescar/config/ConfigFutureTest.java b/config/src/test/java/com/alibaba/fescar/config/ConfigFutureTest.java
new file mode 100644
index 000000000..bf992f01e
--- /dev/null
+++ b/config/src/test/java/com/alibaba/fescar/config/ConfigFutureTest.java
@@ -0,0 +1,130 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  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 com.alibaba.fescar.config;
+
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+/**
+ * @author mawerss1@gmail.com
+ * @date 2019/03/7
+ */
+public class ConfigFutureTest {
+
+    private static final String DATA_ID = "dataId";
+    private static final String CONTENT = "content";
+    private static final String RESULT = "result";
+
+    private static final long TIME_MILLS = 10L;
+    private static final ConfigFuture.ConfigOperation GET_OPERATION = ConfigFuture.ConfigOperation.GET;
+
+    private ConfigFuture configFuture;
+
+    @Before
+    public void initConfigFutureBeforeTest() {
+        configFuture = new ConfigFuture(DATA_ID, CONTENT, GET_OPERATION, TIME_MILLS);
+    }
+
+    /**
+     * Test get with get operation.
+     */
+    @Test
+    public void testConfigGetWithGetOperation() {
+        // return content value when future not set result
+        Assert.assertEquals(CONTENT, configFuture.get());
+        configFuture.setResult(RESULT);
+        Assert.assertEquals(RESULT, configFuture.get());
+    }
+
+    /**
+     * Test get with timeout argument
+     */
+    @Test
+    public void testConfigGetCustomeOutTime() {
+        Assert.assertEquals(CONTENT, configFuture.get(10L, TimeUnit.MILLISECONDS));
+        configFuture.setResult(RESULT);
+        Assert.assertEquals(RESULT, configFuture.get());
+    }
+
+    /**
+     * Test get with put operation.
+     */
+    @Test
+    public void testConfigGetWithPutOperation() {
+        configFuture.setOperation(ConfigFuture.ConfigOperation.PUT);
+        Assert.assertEquals(false, configFuture.get());
+        configFuture.setResult(RESULT);
+        Assert.assertEquals(RESULT, configFuture.get());
+    }
+
+    @Test
+    public void testSetContent() {
+        configFuture.setContent(CONTENT);
+        Assert.assertEquals(CONTENT, configFuture.getContent());
+    }
+
+    @Test
+    public void testGetContent() {
+        configFuture.setContent(CONTENT);
+        Assert.assertEquals(CONTENT, configFuture.getContent());
+    }
+
+    @Test
+    public void testSetDataId() {
+        configFuture.setDataId(DATA_ID);
+        Assert.assertEquals(DATA_ID, configFuture.getDataId());
+    }
+
+    @Test
+    public void testGetDataId() {
+        configFuture.setDataId(DATA_ID);
+        Assert.assertEquals(DATA_ID, configFuture.getDataId());
+    }
+
+    @Test
+    public void testSetResult() {
+        configFuture.setResult(RESULT);
+        Assert.assertEquals(RESULT, configFuture.get());
+    }
+
+    @Test
+    public void testGetOperation() {
+        configFuture.setOperation(ConfigFuture.ConfigOperation.GET);
+        Assert.assertEquals(ConfigFuture.ConfigOperation.GET, configFuture.getOperation());
+    }
+
+    @Test
+    public void testSetOperation() {
+        configFuture.setOperation(ConfigFuture.ConfigOperation.GET);
+        Assert.assertEquals(ConfigFuture.ConfigOperation.GET, configFuture.getOperation());
+    }
+
+    @Test
+    @Ignore
+    public void testIsTimeout() {
+        Assert.assertFalse(configFuture.isTimeout());
+        //TIME_MILLS + 1 ensure timeout occur
+        configFuture.get(TIME_MILLS + 1, TimeUnit.MILLISECONDS);
+        Assert.assertTrue(configFuture.isTimeout());
+    }
+
+}
diff --git a/test/pom.xml b/test/pom.xml
index b8e2eff02..560fc470f 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.4.0</version>
+        <version>0.4.1-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-test</artifactId>