Repository: alibaba/fescar
Pull request #661 (2019-03-26 11:46:55)

Master merges into the develop branch to delete redundant files
<!-- Please make sure you have read and understood the contributing guidelines -->

### Ⅰ. Describe what this PR did


### Ⅱ. 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




Patch:
diff --git a/README.md b/README.md
index 121f15ef7..b6133fb03 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.4.0</fescar.version>
+<fescar.version>0.3.0</fescar.version>
 
 <dependency>
     <groupId>com.alibaba.fescar</groupId>
diff --git a/common/pom.xml b/common/pom.xml
index 4cd902ef9..f8989a200 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.1-SNAPSHOT</version>
+        <version>0.4.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-common</artifactId>
diff --git a/common/src/main/java/com/alibaba/fescar/common/thread/RejectedPolicys.java b/common/src/main/java/com/alibaba/fescar/common/thread/RejectedPolicys.java
new file mode 100644
index 000000000..bfaaf6722
--- /dev/null
+++ b/common/src/main/java/com/alibaba/fescar/common/thread/RejectedPolicys.java
@@ -0,0 +1,54 @@
+/*
+ *  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.common.thread;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * policys for RejectedExecutionHandler
+ *
+ * Created by guoyao on 2019/2/26.
+ */
+public final class RejectedPolicys {
+
+    /**
+     * when rejected happened ,add the new task and run the oldest task
+     *
+     * @return rejected execution handler
+     */
+    public static RejectedExecutionHandler runsOldestTaskPolicy() {
+        return new RejectedExecutionHandler() {
+            @Override
+            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+                if (executor.isShutdown()) {
+                    return;
+                }
+                BlockingQueue<Runnable> workQueue = executor.getQueue();
+                Runnable firstWork = workQueue.poll();
+                boolean newTaskAdd = workQueue.offer(r);
+                if (firstWork != null) {
+                    firstWork.run();
+                }
+                if (!newTaskAdd) {
+                    executor.execute(r);
+                }
+            }
+        };
+    }
+}
diff --git a/config/pom.xml b/config/pom.xml
index b78dbf713..a7356d8ed 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.1-SNAPSHOT</version>
+        <version>0.4.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-config</artifactId>
diff --git a/core/pom.xml b/core/pom.xml
index 1364cd1ad..237f0684e 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.1-SNAPSHOT</version>
+        <version>0.4.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-core</artifactId>
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 de6b57431..2bfc4c7d1 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.1";
+    public static final String CURRENT = "0.4.0";
 
     /**
      * 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 271d5e0bf..c7de72c70 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,8 +18,6 @@ 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 3e2d2e925..aee3d18e8 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,8 +21,6 @@ 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 265e90588..ed86009b8 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,6 +38,8 @@ 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;
 
@@ -88,6 +90,10 @@ 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.
@@ -136,6 +142,7 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
         NettyPoolableFactory keyPoolableFactory = new NettyPoolableFactory(this);
         nettyClientKeyPool = new GenericKeyedObjectPool(keyPoolableFactory);
         nettyClientKeyPool.setConfig(getNettyPoolConfig());
+        serviceManager = new ServiceManagerStaticConfigImpl();
         super.init();
     }
 
@@ -252,7 +259,7 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
             }
             super.destroy();
         } catch (Exception exx) {
-            LOGGER.error("Failed to shutdown: {}", exx.getMessage());
+            LOGGER.error("shutdown error:" + exx.getMessage());
         }
     }
 
@@ -262,7 +269,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;
             }
@@ -277,7 +284,7 @@ public abstract class AbstractRpcRemotingClient extends AbstractRpcRemoting
                 MessageFuture future = futures.remove(msgId);
                 if (future == null) {
                     if (LOGGER.isInfoEnabled()) {
-                        LOGGER.info("msg: {} is not found in futures.", msgId);
+                        LOGGER.info("msg:" + msgId + " is not found in futures.");
                     }
                 } else {
                     future.setResultMessage(results.getMsgs()[i]);
@@ -288,18 +295,6 @@ 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.
      *
@@ -326,27 +321,6 @@ 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.
      *
@@ -384,14 +358,6 @@ 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 1c3cf2518..70714e0bd 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,8 +22,6 @@ 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 e540c9ea4..f572db624 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,6 +16,7 @@
 
 package com.alibaba.fescar.core.rpc.netty;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -40,6 +41,7 @@ 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;
@@ -147,7 +149,7 @@ public final class RmRpcClient extends AbstractRpcRemotingClient {
             timerExecutor.scheduleAtFixedRate(new Runnable() {
                 @Override
                 public void run() {
-                    reconnect(transactionServiceGroup);
+                    reconnect();
                 }
             }, SCHEDULE_INTERVAL_MILLS, SCHEDULE_INTERVAL_MILLS, TimeUnit.SECONDS);
             ExecutorService mergeSendExecutorService = new ThreadPoolExecutor(MAX_MERGE_SEND_THREAD,
@@ -194,6 +196,39 @@ 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()),
@@ -246,8 +281,13 @@ public final class RmRpcClient extends AbstractRpcRemotingClient {
         }
     }
 
-    @Override
-    protected void releaseChannel(Channel channel, String serverAddress) {
+    /**
+     * Release channel.
+     *
+     * @param channel       the channel
+     * @param serverAddress the server address
+     */
+    public 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 cb1efff35..610582fed 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,7 +35,6 @@ 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;
@@ -44,6 +43,7 @@ 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(transactionServiceGroup);
+                    reconnect();
                 } catch (Exception ignore) {
                     LOGGER.error(ignore.getMessage());
                 }
@@ -170,6 +170,39 @@ 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());
@@ -177,7 +210,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);
         }
@@ -240,11 +273,14 @@ public final class TmRpcClient extends AbstractRpcRemotingClient {
 
     }
 
-    @Override
-    protected void releaseChannel(Channel channel, String serverAddress) {
-        if (null == channel || null == serverAddress) {
-            return;
-        }
+    /**
+     * Release channel.
+     *
+     * @param channel       the channel
+     * @param serverAddress the server address
+     */
+    public void releaseChannel(Channel channel, String serverAddress) {
+        if (null == channel || null == serverAddress) { return; }
         try {
             Object connectLock = channelLocks.get(serverAddress);
             synchronized (connectLock) {
@@ -267,6 +303,12 @@ 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
new file mode 100644
index 000000000..245ceb3d9
--- /dev/null
+++ b/core/src/main/java/com/alibaba/fescar/core/service/AddressWatcher.java
@@ -0,0 +1,30 @@
+/*
+ *  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/constants/ConfigurationKeys.java b/core/src/main/java/com/alibaba/fescar/core/service/ConfigurationKeys.java
similarity index 96%
rename from core/src/main/java/com/alibaba/fescar/core/constants/ConfigurationKeys.java
rename to core/src/main/java/com/alibaba/fescar/core/service/ConfigurationKeys.java
index 7fb884fc5..3bd67d29b 100644
--- a/core/src/main/java/com/alibaba/fescar/core/constants/ConfigurationKeys.java
+++ b/core/src/main/java/com/alibaba/fescar/core/service/ConfigurationKeys.java
@@ -14,12 +14,10 @@
  *  limitations under the License.
  */
 
-package com.alibaba.fescar.core.constants;
+package com.alibaba.fescar.core.service;
 
 /**
  * The type Configuration keys.
- *
- * @author jimin.jm @alibaba-inc.com
  */
 public class ConfigurationKeys {
 
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
new file mode 100644
index 000000000..ef316ccca
--- /dev/null
+++ b/core/src/main/java/com/alibaba/fescar/core/service/ServiceManager.java
@@ -0,0 +1,55 @@
+/*
+ *  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
new file mode 100644
index 000000000..45b638152
--- /dev/null
+++ b/core/src/main/java/com/alibaba/fescar/core/service/ServiceManagerStaticConfigImpl.java
@@ -0,0 +1,76 @@
+/*
+ *  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 81903069d..e7b715df0 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.1-SNAPSHOT</version>
+        <version>0.4.0</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 ed72bd31b..b4fb24c6b 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,10 +22,12 @@ 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;
@@ -39,8 +41,6 @@ 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,7 +49,6 @@ import org.slf4j.LoggerFactory;
  * @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";
@@ -60,7 +59,6 @@ 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";
@@ -97,7 +95,7 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
             instanceConfig.setApplicationName(getApplicationName());
             instanceConfig.setInstanceId(getInstanceId());
         }
-        getEurekaClient(true);
+        getEurekaClient();
         applicationInfoManager.setInstanceStatus(InstanceInfo.InstanceStatus.UP);
     }
 
@@ -113,14 +111,16 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
 
     @Override
     public void subscribe(String cluster, EurekaEventListener listener) throws Exception {
+        assertEureka();
         subscribeListener = true;
-        getEurekaClient(false).registerEventListener(listener);
+        eurekaClient.registerEventListener(listener);
     }
 
     @Override
     public void unsubscribe(String cluster, EurekaEventListener listener) throws Exception {
+        assertEureka();
         subscribeListener = false;
-        getEurekaClient(false).unregisterEventListener(listener);
+        eurekaClient.unregisterEventListener(listener);
     }
 
     @Override
@@ -131,16 +131,14 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
             return null;
         }
 
+        assertEureka();
+
         if (!subscribeListener) {
             refreshCluster();
             subscribe(null, new EurekaEventListener() {
                 @Override
                 public void onEvent(EurekaEvent event) {
-                    try {
-                        refreshCluster();
-                    } catch (Exception e) {
-                        LOGGER.error("Eureka event listener refreshCluster error!");
-                    }
+                    refreshCluster();
                 }
             });
         }
@@ -148,8 +146,8 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
         return Lists.newArrayList(CLUSTER_ADDRESS_MAP.get(clusterName.toUpperCase()));
     }
 
-    private static void refreshCluster() throws EurekaRegistryException{
-        Applications applications = getEurekaClient(false).getApplications();
+    private static void refreshCluster() {
+        Applications applications = eurekaClient.getApplications();
         List<Application> list = applications.getRegisteredApplications();
         if (list == null || list.isEmpty()) {
             CLUSTER_ADDRESS_MAP.clear();
@@ -174,7 +172,7 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
         eurekaClient = null;
     }
 
-    private static Properties getEurekaProperties(boolean needRegister) {
+    private static Properties getEurekaProperties() {
         Properties eurekaProperties = new Properties();
         eurekaProperties.setProperty(EUREKA_CONFIG_REFRESH_KEY, String.valueOf(EUREKA_REFRESH_INTERVAL));
 
@@ -191,10 +189,6 @@ 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;
     }
 
@@ -206,20 +200,16 @@ public class EurekaRegistryServiceImpl implements RegistryService<EurekaEventLis
         return application;
     }
 
-    private static EurekaClient getEurekaClient(boolean needRegister) throws EurekaRegistryException{
+    private static EurekaClient getEurekaClient() throws Exception {
         if (eurekaClient == null) {
             synchronized (EurekaRegistryServiceImpl.class) {
                 try {
-                    if (eurekaClient != null) {
-                        return eurekaClient;
+                    if (eurekaClient == null) {
+                        ConfigurationManager.loadProperties(getEurekaProperties());
+                        InstanceInfo instanceInfo = new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get();
+                        applicationInfoManager = new ApplicationInfoManager(instanceConfig, instanceInfo);
+                        eurekaClient = new DiscoveryClient(applicationInfoManager, new DefaultEurekaClientConfig());
                     }
-                    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);
@@ -229,6 +219,12 @@ 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 9c6759877..1f68d0432 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.1-SNAPSHOT</version>
+        <version>0.4.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-distribution</artifactId>
diff --git a/dubbo-alibaba/pom.xml b/dubbo-alibaba/pom.xml
index c15ec241f..eec324ed8 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.1-SNAPSHOT</version>
+        <version>0.4.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/dubbo/pom.xml b/dubbo/pom.xml
index e5299e739..0cc8f7ce3 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.1-SNAPSHOT</version>
+        <version>0.4.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-dubbo</artifactId>
diff --git a/pom.xml b/pom.xml
index 1c2a01e30..93b88cf1c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
 
     <groupId>com.alibaba.fescar</groupId>
     <artifactId>fescar-all</artifactId>
-    <version>0.4.1-SNAPSHOT</version>
+    <version>0.4.0</version>
     <modules>
         <module>config</module>
         <module>common</module>
diff --git a/rm-datasource/pom.xml b/rm-datasource/pom.xml
index 017756a63..8dc2f47d7 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.1-SNAPSHOT</version>
+        <version>0.4.0</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 00702a8c5..d94e77285 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.constants.ConfigurationKeys.CLIENT_ASYNC_COMMIT_BUFFER_LIMIT;
+import static com.alibaba.fescar.core.service.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 fbbce1244..99eeba870 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,7 +23,6 @@ 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;
@@ -31,8 +30,6 @@ 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;
 
 /**
@@ -57,13 +54,12 @@ public class DeleteExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
 
     @Override
     protected TableRecords beforeImage() throws SQLException {
-        SQLDeleteRecognizer visitor = (SQLDeleteRecognizer) sqlRecognizer;
-        KeywordChecker keywordChecker = KeywordCheckerFactory.getKeywordChecker(JdbcConstants.MYSQL);
+        SQLDeleteRecognizer visitor = (SQLDeleteRecognizer)sqlRecognizer;
 
         TableMeta tmeta = getTableMeta(visitor.getTableName());
         List<String> columns = new ArrayList<>();
         for (String column : tmeta.getAllColumns().keySet()) {
-            columns.add(keywordChecker.checkAndReplace(column));
+            columns.add(column);
         }
 
         StringBuffer selectSQLAppender = new StringBuffer("SELECT ");
@@ -77,11 +73,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 " + keywordChecker.checkAndReplace(getFromTableInSQL()));
+        selectSQLAppender.append(" FROM " + 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 6dbc6bbfe..cd08d11fc 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.constants.ConfigurationKeys;
+import com.alibaba.fescar.core.service.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 727d84600..63ca8db2d 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,22 +18,18 @@ package com.alibaba.fescar.rm.datasource.undo.mysql.keyword;
 
 import com.alibaba.fescar.rm.datasource.undo.KeywordChecker;
 
-import java.util.Arrays;
-import java.util.Set;
-import java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
 
 /**
  * The type My sql keyword checker.
  *
- * @author xingfudeshi@gmail.com
- * @date 2019/3/5 MySQL keyword checker
+ * @author Wu
+ * @date 2019 /3/5 MySQL keyword checker
  */
 public class MySQLKeywordChecker implements KeywordChecker {
-    private static volatile KeywordChecker keywordChecker = null;
-    private static volatile Set<String> keywordSet = null;
+    private static volatile KeywordChecker keywordChecker;
 
-    private MySQLKeywordChecker() {
-    }
+    private MySQLKeywordChecker() {}
 
     /**
      * get instance of type MySQL keyword checker
@@ -45,7 +41,6 @@ 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());
                 }
             }
         }
@@ -529,27 +524,30 @@ public class MySQLKeywordChecker implements KeywordChecker {
          */
         public final String name;
 
+        MySQLKeyword() {
+            this(null);
+        }
+
         MySQLKeyword(String name) {
             this.name = name;
         }
     }
 
-
     @Override
     public boolean check(String fieldOrTableName) {
-        if (keywordSet.contains(fieldOrTableName)) {
-            return true;
-        }
-        if (null != fieldOrTableName) {
-            fieldOrTableName = fieldOrTableName.toUpperCase();
+        try {
+            if (StringUtils.isNotBlank(fieldOrTableName)) {
+                MySQLKeyword.valueOf(fieldOrTableName.toUpperCase());
+                return true;
+            }
+        } catch (IllegalArgumentException e) {
+            //do nothing
         }
-        return keywordSet.contains(fieldOrTableName);
-
+        return false;
     }
 
     @Override
     public String checkAndReplace(String fieldOrTableName) {
         return check(fieldOrTableName) ? "`" + fieldOrTableName + "`" : fieldOrTableName;
     }
-
 }
diff --git a/rm/pom.xml b/rm/pom.xml
index e478e7d56..0a0b90595 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.1-SNAPSHOT</version>
+        <version>0.4.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-rm</artifactId>
diff --git a/server/pom.xml b/server/pom.xml
index ef18a791d..44d217f15 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.1-SNAPSHOT</version>
+        <version>0.4.0</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 b7f31825f..76eea6b46 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 85102a852..c19c5455a 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.1-SNAPSHOT</version>
+        <version>0.4.0</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 5e3b856b0..d18053000 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,7 +19,6 @@ 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;
@@ -141,10 +140,21 @@ public class GlobalTransactionalInterceptor implements MethodInterceptor {
     }
 
     private String formatMethod(Method method) {
-        String paramTypes = Arrays.stream(method.getParameterTypes())
-                .map(Class::getName)
-                .reduce((p1, p2) -> String.format("%s, %s", p1, p2))
-                .orElse("");
-        return method.getName() + "(" + paramTypes + ")";
+        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();
     }
 }
diff --git a/tcc/pom.xml b/tcc/pom.xml
index b71b78604..c7fc5f18d 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.1-SNAPSHOT</version>
+        <version>0.4.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-tcc</artifactId>
diff --git a/tm/pom.xml b/tm/pom.xml
index 2cdbc8472..a95e9123a 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.1-SNAPSHOT</version>
+        <version>0.4.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-tm</artifactId>


Test patch:
diff --git a/common/src/test/java/com/alibaba/fescar/common/thread/RejectedPolicysTest.java b/common/src/test/java/com/alibaba/fescar/common/thread/RejectedPolicysTest.java
new file mode 100644
index 000000000..64e90e715
--- /dev/null
+++ b/common/src/test/java/com/alibaba/fescar/common/thread/RejectedPolicysTest.java
@@ -0,0 +1,97 @@
+/*
+ *  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.common.thread;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Created by guoyao on 2019/2/26.
+ */
+public class RejectedPolicysTest {
+
+    private final int DEFAULT_CORE_POOL_SIZE = 1;
+    private final int DEFAULT_KEEP_ALIVE_TIME = 10;
+    private final int MAX_QUEUE_SIZE = 1;
+
+    /**
+     * Test runs oldest task policy.
+     *
+     * @throws Exception the exception
+     */
+    @Test
+    public void testRunsOldestTaskPolicy() throws Exception {
+        AtomicInteger atomicInteger = new AtomicInteger();
+        ThreadPoolExecutor poolExecutor =
+            new ThreadPoolExecutor(DEFAULT_CORE_POOL_SIZE, DEFAULT_CORE_POOL_SIZE, DEFAULT_KEEP_ALIVE_TIME,
+                TimeUnit.MILLISECONDS,
+                new LinkedBlockingQueue(MAX_QUEUE_SIZE),
+                new NamedThreadFactory("OldestRunsPolicy", DEFAULT_CORE_POOL_SIZE),
+                RejectedPolicys.runsOldestTaskPolicy());
+        CountDownLatch downLatch1 = new CountDownLatch(1);
+        CountDownLatch downLatch2 = new CountDownLatch(1);
+        CountDownLatch downLatch3 = new CountDownLatch(1);
+        //task1
+        poolExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    //wait the oldest task of queue count down
+                    downLatch1.await();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                atomicInteger.getAndAdd(1);
+            }
+        });
+        assertThat(atomicInteger.get()).isEqualTo(0);
+        //task2
+        poolExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                // run second
+                atomicInteger.getAndAdd(2);
+            }
+        });
+        //task3
+        poolExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                downLatch2.countDown();
+                //task3 run
+                atomicInteger.getAndAdd(3);
+                downLatch3.countDown();
+            }
+        });
+        //only the task2 run which is the oldest task of queue
+        assertThat(atomicInteger.get()).isEqualTo(2);
+        downLatch1.countDown();
+        downLatch2.await();
+        //wait task3 run +3
+        downLatch3.await();
+        //run task3
+        assertThat(atomicInteger.get()).isEqualTo(6);
+
+    }
+}
diff --git a/config/src/test/java/com/alibaba/fescar/config/ConfigFutureTest.java b/config/src/test/java/com/alibaba/fescar/config/ConfigFutureTest.java
deleted file mode 100644
index bf992f01e..000000000
--- a/config/src/test/java/com/alibaba/fescar/config/ConfigFutureTest.java
+++ /dev/null
@@ -1,130 +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.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/core/src/test/java/com/alibaba/fescar/core/protocol/transaction/GlobalBeginResponseTest.java b/core/src/test/java/com/alibaba/fescar/core/protocol/transaction/GlobalBeginResponseTest.java
deleted file mode 100644
index 84bbbafdd..000000000
--- a/core/src/test/java/com/alibaba/fescar/core/protocol/transaction/GlobalBeginResponseTest.java
+++ /dev/null
@@ -1,70 +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.protocol.transaction;
-
-import com.alibaba.fescar.core.protocol.ResultCode;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.nio.ByteBuffer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * A unit test for {@link GlobalBeginResponse}
- *
- * @author liujc
- * @date 2019/3/22 11:09
- **/
-public class GlobalBeginResponseTest {
-    private final String XID = "test_xid";
-    private final String EXTRA_DATA = "test_extra_data";
-    private final ResultCode RESULT_CODE = ResultCode.Success;
-
-    @Test
-    public void testGetSetXid() {
-        GlobalBeginResponse globalBeginResponse = new GlobalBeginResponse();
-        globalBeginResponse.setXid(XID);
-        Assert.assertEquals(XID, globalBeginResponse.getXid());
-    }
-
-    @Test
-    public void testGetSetExtraData() {
-        GlobalBeginResponse globalBeginResponse = new GlobalBeginResponse();
-        globalBeginResponse.setExtraData(EXTRA_DATA);
-        Assert.assertEquals(EXTRA_DATA, globalBeginResponse.getExtraData());
-    }
-
-    @Test
-    public void testGetTypeCode() {
-        GlobalBeginResponse globalBeginResponse = new GlobalBeginResponse();
-        Assert.assertEquals(GlobalBeginResponse.TYPE_GLOBAL_BEGIN_RESULT, globalBeginResponse.getTypeCode());
-    }
-
-    @Test
-    public void testDoEncodeAndDecode() {
-        GlobalBeginResponse globalBeginResponseOne = new GlobalBeginResponse();
-        globalBeginResponseOne.setXid(XID);
-        globalBeginResponseOne.setExtraData(EXTRA_DATA);
-        globalBeginResponseOne.setResultCode(RESULT_CODE);
-        byte[] encode = globalBeginResponseOne.encode();
-        GlobalBeginResponse globalBeginResponseTwo = new GlobalBeginResponse();
-        globalBeginResponseTwo.decode(ByteBuffer.wrap(encode));
-        assertThat(globalBeginResponseOne.getXid()).isEqualTo(globalBeginResponseTwo.getXid());
-        assertThat(globalBeginResponseOne.getExtraData()).isEqualTo(globalBeginResponseTwo.getExtraData());
-        assertThat(globalBeginResponseOne.getResultCode()).isEqualTo(globalBeginResponseTwo.getResultCode());
-    }
-}
diff --git a/test/pom.xml b/test/pom.xml
index 560fc470f..b8e2eff02 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.1-SNAPSHOT</version>
+        <version>0.4.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-test</artifactId>