diff --git a/java/core/client.pom.xml b/java/core/client.pom.xml
index 64f0c861a..f5c69b9cf 100644
--- a/java/core/client.pom.xml
+++ b/java/core/client.pom.xml
@@ -6,7 +6,7 @@
qq-cloud-central
tars-parent
- 1.0.2
+ 1.0.3
tars-client
${project.artifactId}
diff --git a/java/core/pom.xml b/java/core/pom.xml
index 3990b4f78..2625a4fe7 100644
--- a/java/core/pom.xml
+++ b/java/core/pom.xml
@@ -6,7 +6,7 @@
qq-cloud-central
tars-parent
- 1.0.2
+ 1.0.3
tars-core
${project.artifactId}
diff --git a/java/core/server.pom.xml b/java/core/server.pom.xml
index 1e7a5fa83..3c4e15028 100644
--- a/java/core/server.pom.xml
+++ b/java/core/server.pom.xml
@@ -6,7 +6,7 @@
qq-cloud-central
tars-parent
- 1.0.2
+ 1.0.3
tars-server
${project.artifactId}
diff --git a/java/core/src/main/java/com/qq/tars/client/Communicator.java b/java/core/src/main/java/com/qq/tars/client/Communicator.java
index 6bfcd14ef..7fb71f319 100644
--- a/java/core/src/main/java/com/qq/tars/client/Communicator.java
+++ b/java/core/src/main/java/com/qq/tars/client/Communicator.java
@@ -60,13 +60,13 @@ public T stringToProxy(Class clazz, ServantProxyConfig servantProxyConfig
return stringToProxy(clazz, servantProxyConfig, null);
}
- public T stringToProxy(Class clazz, ServantProxyConfig servantProxyConfig, LoadBalance loadBalance) throws CommunicatorConfigException {
+ public T stringToProxy(Class clazz, ServantProxyConfig servantProxyConfig, LoadBalance loadBalance) throws CommunicatorConfigException {
return stringToProxy(clazz, servantProxyConfig.getObjectName(), servantProxyConfig, loadBalance, null);
}
@SuppressWarnings("unchecked")
private T stringToProxy(Class clazz, String objName, ServantProxyConfig servantProxyConfig,
- LoadBalance loadBalance, ProtocolInvoker protocolInvoker) throws CommunicatorConfigException {
+ LoadBalance loadBalance, ProtocolInvoker protocolInvoker) throws CommunicatorConfigException {
if (!inited.get()) {
throw new CommunicatorConfigException("communicator uninitialized!");
}
diff --git a/java/core/src/main/java/com/qq/tars/client/ObjectProxy.java b/java/core/src/main/java/com/qq/tars/client/ObjectProxy.java
index 7665510b2..f77d49fc4 100644
--- a/java/core/src/main/java/com/qq/tars/client/ObjectProxy.java
+++ b/java/core/src/main/java/com/qq/tars/client/ObjectProxy.java
@@ -50,6 +50,8 @@ public final class ObjectProxy implements ServantProxy, InvocationHandler {
private ScheduledFuture> statReportFuture;
private ScheduledFuture> queryRefreshFuture;
+ private final Object refreshLock = new Object();
+
private final Random random = new Random(System.currentTimeMillis() / 1000);
public ObjectProxy(Class api, String objName, ServantProxyConfig servantProxyConfig, LoadBalance loadBalance,
@@ -89,7 +91,7 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
return null;
}
- Invoker invoker = loadBalancer.select(protocolInvoker.getInvokers(), context);
+ Invoker invoker = loadBalancer.select(context);
return invoker.invoke(context);
} catch (Throwable e) {
if (ClientLogger.getLogger().isDebugEnabled()) {
@@ -111,9 +113,12 @@ public String getObjectName() {
}
public void refresh() {
- registryStatReproter();
- registryServantNodeRefresher();
- protocolInvoker.refresh();
+ synchronized (refreshLock) {
+ registryStatReproter();
+ registryServantNodeRefresher();
+ protocolInvoker.refresh();
+ loadBalancer.refresh(protocolInvoker.getInvokers());
+ }
}
public void destroy() {
@@ -127,6 +132,8 @@ public ServantProxyConfig getConfig() {
}
private void initialize() {
+ loadBalancer.refresh(protocolInvoker.getInvokers());
+
if (StringUtils.isNotEmpty(this.servantProxyConfig.getLocator()) && !StringUtils.isEmpty(this.servantProxyConfig.getStat())) {
this.registryStatReproter();
}
diff --git a/java/core/src/main/java/com/qq/tars/client/ObjectProxyFactory.java b/java/core/src/main/java/com/qq/tars/client/ObjectProxyFactory.java
index 10c85953a..174c50976 100644
--- a/java/core/src/main/java/com/qq/tars/client/ObjectProxyFactory.java
+++ b/java/core/src/main/java/com/qq/tars/client/ObjectProxyFactory.java
@@ -18,7 +18,8 @@
import java.lang.reflect.Constructor;
-import com.qq.tars.client.cluster.DefaultLoadBalance;
+
+import com.qq.tars.client.rpc.loadbalance.DefaultLoadBalance;
import com.qq.tars.client.rpc.tars.TarsProtocolInvoker;
import com.qq.tars.client.support.ServantCacheManager;
import com.qq.tars.client.util.ClientLogger;
@@ -42,7 +43,7 @@ public ObjectProxyFactory(Communicator communicator) {
}
public ObjectProxy getObjectProxy(Class api, String objName, ServantProxyConfig servantProxyConfig,
- LoadBalance loadBalance, ProtocolInvoker protocolInvoker) throws ClientException {
+ LoadBalance loadBalance, ProtocolInvoker protocolInvoker) throws ClientException {
if (servantProxyConfig == null) {
servantProxyConfig = createServantProxyConfig(objName);
} else {
@@ -77,8 +78,8 @@ private ProtocolInvoker createProtocolInvoker(Class api, String objNam
return protocolInvoker;
}
- private LoadBalance createLoadBalance(ServantProxyConfig servantProxyConfig) {
- return new DefaultLoadBalance(servantProxyConfig);
+ private LoadBalance createLoadBalance(ServantProxyConfig servantProxyConfig) {
+ return new DefaultLoadBalance(servantProxyConfig);
}
private Codec createCodec(Class api, ServantProxyConfig servantProxyConfig) throws ClientException {
diff --git a/java/core/src/main/java/com/qq/tars/client/ServantProxyConfig.java b/java/core/src/main/java/com/qq/tars/client/ServantProxyConfig.java
index f8c6ddef5..cc48a68b8 100644
--- a/java/core/src/main/java/com/qq/tars/client/ServantProxyConfig.java
+++ b/java/core/src/main/java/com/qq/tars/client/ServantProxyConfig.java
@@ -53,6 +53,11 @@ public final class ServantProxyConfig {
private boolean directConnection = false;
+ private int minStaticWeightLimit = 10;
+ private int maxStaticWeightLimit = 100;
+
+ private int defaultConHashVirtualNodes = 100;
+
public ServantProxyConfig(String objectName) {
this(null, null, objectName);
}
@@ -269,6 +274,31 @@ public void setReportInterval(int reportInterval) {
this.reportInterval = reportInterval;
}
+ public int getMaxStaticWeightLimit() {
+ return maxStaticWeightLimit;
+ }
+
+ public void setMaxStaticWeightLimit(int maxStaticWeightLimit) {
+ this.maxStaticWeightLimit = maxStaticWeightLimit;
+ }
+
+
+ public int getMinStaticWeightLimit() {
+ return minStaticWeightLimit;
+ }
+
+ public void setMinStaticWeightLimit(int minStaticWeightLimit) {
+ this.minStaticWeightLimit = minStaticWeightLimit;
+ }
+
+ public int getDefaultConHashVirtualNodes() {
+ return defaultConHashVirtualNodes;
+ }
+
+ public void setDefaultConHashVirtualNodes(int defaultConHashVirtualNodes) {
+ this.defaultConHashVirtualNodes = defaultConHashVirtualNodes;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
diff --git a/java/core/src/main/java/com/qq/tars/client/cluster/DefaultLoadBalance.java b/java/core/src/main/java/com/qq/tars/client/cluster/DefaultLoadBalance.java
index 48ac739e8..dbcc1ff31 100644
--- a/java/core/src/main/java/com/qq/tars/client/cluster/DefaultLoadBalance.java
+++ b/java/core/src/main/java/com/qq/tars/client/cluster/DefaultLoadBalance.java
@@ -32,7 +32,8 @@
import com.qq.tars.rpc.common.LoadBalance;
import com.qq.tars.rpc.common.exc.NoInvokerException;
-public class DefaultLoadBalance implements LoadBalance {
+@Deprecated
+public class DefaultLoadBalance {
private final AtomicInteger sequence = new AtomicInteger();
private volatile ServantProxyConfig config;
diff --git a/java/core/src/main/java/com/qq/tars/client/util/ParseTools.java b/java/core/src/main/java/com/qq/tars/client/util/ParseTools.java
index 522620c92..196f9ee82 100644
--- a/java/core/src/main/java/com/qq/tars/client/util/ParseTools.java
+++ b/java/core/src/main/java/com/qq/tars/client/util/ParseTools.java
@@ -73,6 +73,9 @@ private static Url parse(String objectName, String content, ServantProxyConfig c
int active = 1;
String setDivision = null;
+ String enableAuth = "0";
+ int weightType = 0;
+ int weight = 0;
for (int i = 0; i < items.length; i++) {
if (items[i].equals("-h")) {
host = items[i + 1];
@@ -82,6 +85,12 @@ private static Url parse(String objectName, String content, ServantProxyConfig c
active = Integer.parseInt(items[i + 1]);
} else if (items[i].equals("-s")) {
setDivision = items[i + 1];
+ } else if (items[i].equals("-e")) {
+ enableAuth = items[i + 1];
+ } else if (items[i].equals("-v")) {
+ weightType = Integer.parseInt(items[i + 1]);
+ } else if (items[i].equals("-w")) {
+ weight = Integer.parseInt(items[i + 1]);
}
}
if (StringUtils.isEmpty(host) || port == -1) {
@@ -98,6 +107,10 @@ private static Url parse(String objectName, String content, ServantProxyConfig c
parameters.put(Constants.TARS_CLIENT_UDPMODE, Boolean.toString(items[0].toLowerCase().equals("udp")));
parameters.put(Constants.TARS_CLIENT_TCPNODELAY, Boolean.toString(conf.isTcpNoDelay()));
parameters.put(Constants.TARS_CLIENT_CHARSETNAME, conf.getCharsetName());
+ parameters.put(Constants.TARS_CLIENT_ENABLEAUTH, enableAuth);
+ parameters.put(Constants.TARS_CLIENT_WEIGHT_TYPE, String.valueOf(weightType));
+ parameters.put(Constants.TARS_CLIENT_WEIGHT, String.valueOf(weight));
+
return new Url(conf.getProtocol(), host, port, objectName, parameters);
}
}
diff --git a/java/core/src/main/java/com/qq/tars/common/util/Constants.java b/java/core/src/main/java/com/qq/tars/common/util/Constants.java
index d03aaf475..ab7e0c4ff 100644
--- a/java/core/src/main/java/com/qq/tars/common/util/Constants.java
+++ b/java/core/src/main/java/com/qq/tars/common/util/Constants.java
@@ -72,8 +72,14 @@ public interface Constants {
String TARS_CLIENT_CHARSETNAME = "charsetName";
String TARS_HASH = "tars_hash";
+ String TARS_CONSISTENT_HASH = "taf_consistent_hash";
String TARS_TUP_CLIENT = "tup_client";
String TARS_ONE_WAY_CLIENT = "one_way_client";
String TARS_NOT_CLIENT = "not_tars_client";
+ String TARS_CLIENT_ENABLEAUTH = "enableAuth";
+
+ String TARS_CLIENT_WEIGHT_TYPE = "weightType";
+ String TARS_CLIENT_WEIGHT = "weight";
+ String TARS_CLIENT_GRAYFLAG = "taf.framework.GrayFlag";
}
diff --git a/java/core/src/main/java/com/qq/tars/rpc/common/LoadBalance.java b/java/core/src/main/java/com/qq/tars/rpc/common/LoadBalance.java
index f0b49d0a6..f4db6f25a 100644
--- a/java/core/src/main/java/com/qq/tars/rpc/common/LoadBalance.java
+++ b/java/core/src/main/java/com/qq/tars/rpc/common/LoadBalance.java
@@ -20,7 +20,20 @@
import com.qq.tars.rpc.common.exc.NoInvokerException;
-public interface LoadBalance {
+public interface LoadBalance {
- Invoker select(Collection> invokers, InvokeContext context) throws NoInvokerException;
+ /**
+ * 根据负载均衡策略,挑选invoker
+ *
+ * @param invokeContext
+ * @return
+ * @throws NoInvokerException
+ */
+ Invoker select(InvokeContext invokeContext) throws NoInvokerException;
+
+ /**
+ * 通知invoker列表的更新
+ * @param invokers
+ */
+ void refresh(Collection> invokers);
}
diff --git a/java/core/src/main/java/com/qq/tars/server/ServerVersion.java b/java/core/src/main/java/com/qq/tars/server/ServerVersion.java
index ece3d461d..4f1ccc910 100644
--- a/java/core/src/main/java/com/qq/tars/server/ServerVersion.java
+++ b/java/core/src/main/java/com/qq/tars/server/ServerVersion.java
@@ -20,7 +20,7 @@ public final class ServerVersion {
public static final String major = "1";
public static final String minor = "0";
- public static final String build = "1";
+ public static final String build = "3";
public static String getVersion() {
return major + "." + minor + "." + build;
diff --git a/java/core/src/main/java/com/qq/tars/server/apps/BaseAppContext.java b/java/core/src/main/java/com/qq/tars/server/apps/BaseAppContext.java
new file mode 100644
index 000000000..ff19ed0fe
--- /dev/null
+++ b/java/core/src/main/java/com/qq/tars/server/apps/BaseAppContext.java
@@ -0,0 +1,122 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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.qq.tars.server.apps;
+
+import com.qq.tars.rpc.protocol.ext.ExtendedServant;
+import com.qq.tars.rpc.protocol.tars.support.AnalystManager;
+import com.qq.tars.server.config.ConfigurationManager;
+import com.qq.tars.server.config.ServantAdapterConfig;
+import com.qq.tars.server.config.ServerConfig;
+import com.qq.tars.server.core.*;
+import com.qq.tars.server.core.AppContext;
+import com.qq.tars.support.admin.AdminFServant;
+import com.qq.tars.support.admin.impl.AdminFServantImpl;
+import com.qq.tars.support.om.OmConstants;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class BaseAppContext implements AppContext {
+ protected File path = null;
+ boolean ready = true;
+
+ ConcurrentHashMap skeletonMap = new ConcurrentHashMap();
+ ConcurrentHashMap servantAdapterMap = new ConcurrentHashMap();
+
+ HashMap contextParams = new HashMap();
+
+ Set listeners = new HashSet(4);
+
+ BaseAppContext(File path) {
+ this.path = path;
+ }
+
+ void injectAdminServant() {
+ try {
+ String skeletonName = OmConstants.AdminServant;
+ ServantHomeSkeleton skeleton = new ServantHomeSkeleton(skeletonName, new AdminFServantImpl(), AdminFServant.class, null, null, -1);
+ skeleton.setAppContext(this);
+
+ ServerConfig serverCfg = ConfigurationManager.getInstance().getServerConfig();
+ ServantAdapterConfig config = serverCfg.getServantAdapterConfMap().get(OmConstants.AdminServant);
+ ServantAdapter servantAdapter = new ServantAdapter(config);
+ servantAdapter.bind(skeleton);
+ servantAdapterMap.put(skeletonName, servantAdapter);
+
+ skeletonMap.put(skeletonName, skeleton);
+ } catch (Exception e) {
+ System.err.println("init om service failed:context=[]");
+ e.printStackTrace();
+ }
+ }
+
+ void appServantStarted(AppService appService) {
+ for (AppContextListener listener : listeners) {
+ listener.appServantStarted(new DefaultAppServantEvent(appService));
+ }
+ }
+
+ void initServants() {
+ for (String skeletonName : skeletonMap.keySet()) {
+ ServantHomeSkeleton skeleton = skeletonMap.get(skeletonName);
+ Class> api = skeleton.getApiClass();
+ try {
+ if (api.isAssignableFrom(ExtendedServant.class)) {
+ continue;
+ }
+ AnalystManager.getInstance().registry(name(), api, skeleton.name());
+ } catch (Exception e) {
+ System.err.println("app[] init servant[" + api.getName() + "] failed");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ void appContextStarted() {
+ for (AppContextListener listener : listeners) {
+ listener.appContextStarted(new DefaultAppContextEvent(this));
+ }
+ }
+
+ @Override
+ public String getInitParameter(String name) {
+ return contextParams.get(name);
+ }
+
+ @Override
+ public String name() {
+ return "";
+ }
+
+ @Override
+ public void stop() {
+ for (Adapter servantAdapter : servantAdapterMap.values()) {
+ servantAdapter.stop();
+ }
+ }
+
+ @Override
+ public ServantHomeSkeleton getCapHomeSkeleton(String homeName) {
+ if (!ready) {
+ throw new RuntimeException("The application isn't started.");
+ }
+ return skeletonMap.get(homeName);
+ }
+}
diff --git a/java/core/src/main/java/com/qq/tars/server/apps/XmlAppContext.java b/java/core/src/main/java/com/qq/tars/server/apps/XmlAppContext.java
new file mode 100644
index 000000000..1ffeb8f84
--- /dev/null
+++ b/java/core/src/main/java/com/qq/tars/server/apps/XmlAppContext.java
@@ -0,0 +1,168 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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.qq.tars.server.apps;
+
+import com.qq.tars.common.util.StringUtils;
+import com.qq.tars.net.core.Processor;
+import com.qq.tars.protocol.annotation.Servant;
+import com.qq.tars.protocol.util.TarsHelper;
+import com.qq.tars.rpc.protocol.Codec;
+import com.qq.tars.server.common.XMLConfigElement;
+import com.qq.tars.server.common.XMLConfigFile;
+import com.qq.tars.server.config.ConfigurationManager;
+import com.qq.tars.server.config.ServantAdapterConfig;
+import com.qq.tars.server.config.ServerConfig;
+import com.qq.tars.server.core.AppContextListener;
+import com.qq.tars.server.core.ServantAdapter;
+import com.qq.tars.server.core.ServantHomeSkeleton;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class XmlAppContext extends BaseAppContext {
+ public XmlAppContext(File path) {
+ super(path);
+ try {
+ initFromConfigFile();
+ injectAdminServant();
+ initServants();
+ appContextStarted();
+ System.out.println("[SERVER] The application started successfully. {appname=}");
+ } catch (Exception ex) {
+ ready = false;
+ System.out.println("[SERVER] failed to start the applicaton. {appname=}");
+ }
+ }
+
+ private void initFromConfigFile() throws Exception {
+ if (path.exists()) {
+ XMLConfigFile cfg = new XMLConfigFile();
+ cfg.parse(new FileInputStream(path));
+ XMLConfigElement root = cfg.getRootElement();
+ ArrayList elements = root.getChildList();
+
+ loadInitParams(root.getChildListByName("context-param"));
+
+ loadAppContextListeners(elements);
+
+ loadAppServants(elements);
+ } else {
+ System.err.println("servants.xml is not exists");
+ }
+ }
+
+ private void loadInitParams(ArrayList list) {
+ if (list == null || list.isEmpty()) return;
+ for (XMLConfigElement e : list) {
+ String name = getChildNodeValue(e, "param-name");
+ String value = getChildNodeValue(e, "param-value");
+ if (!StringUtils.isEmpty(name)) contextParams.put(name, value);
+ }
+ }
+
+ private void loadAppContextListeners(ArrayList elements) {
+ for (XMLConfigElement element : elements) {
+ if ("listener".equals(element.getName())) {
+ String listenerClass = getChildNodeValue(element, "listener-class");
+ AppContextListener listener;
+
+ try {
+ listener = (AppContextListener) Class.forName(listenerClass).newInstance();
+ listeners.add(listener);
+ } catch (ClassNotFoundException e) {
+ System.err.println("invalid listener config|ClassNotFoundException:" + listenerClass);
+ } catch (ClassCastException e) {
+ System.err.println("invalid listener config|It is NOT a ContextListener:" + listenerClass);
+ } catch (Exception e) {
+ System.err.println("create listener instance failed.");
+ }
+ }
+ }
+ }
+
+ private void loadAppServants(ArrayList elements) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+ for (XMLConfigElement element : elements) {
+ if ("servant".equals(element.getName())) {
+ try {
+ ServantHomeSkeleton skeleton = loadServant(element);
+ skeletonMap.put(skeleton.name(), skeleton);
+ appServantStarted(skeleton);
+ } catch (Exception e) {
+ System.err.println("init a service failed:context=[]");
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private ServantHomeSkeleton loadServant(XMLConfigElement element) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
+ String homeName = null, homeApiName = null, homeClassName = null, processorClazzName = null,
+ codecClazzName = null;
+ Class> homeApiClazz = null;
+ Class extends Codec> codecClazz = null;
+ Class extends Processor> processorClazz = null;
+ Object homeClassImpl = null;
+ ServantHomeSkeleton skeleton = null;
+ int maxLoadLimit = -1;
+
+ ServerConfig serverCfg = ConfigurationManager.getInstance().getServerConfig();
+
+ homeName = element.getStringAttribute("name");
+ if (StringUtils.isEmpty(homeName)) {
+ throw new RuntimeException("servant name is null.");
+ }
+ homeName = String.format("%s.%s.%s", serverCfg.getApplication(), serverCfg.getServerName(), homeName);
+ homeApiName = getChildNodeValue(element, "home-api");
+ homeClassName = getChildNodeValue(element, "home-class");
+ processorClazzName = getChildNodeValue(element, "home-processor-class");
+ codecClazzName = getChildNodeValue(element, "home-codec-class");
+
+ homeApiClazz = Class.forName(homeApiName);
+ homeClassImpl = Class.forName(homeClassName).newInstance();
+ codecClazz = (Class extends Codec>) (StringUtils.isEmpty(codecClazzName) ? null : Class.forName(codecClazzName));
+ processorClazz = (Class extends Processor>) (StringUtils.isEmpty(processorClazzName) ? null : Class.forName(processorClazzName));
+
+ if (TarsHelper.isServant(homeApiClazz)) {
+ String servantName = homeApiClazz.getAnnotation(Servant.class).name();
+ if (!StringUtils.isEmpty(servantName) && servantName.matches("^[\\w]+\\.[\\w]+\\.[\\w]+$")) {
+ homeName = servantName;
+ }
+ }
+
+ ServantAdapterConfig servantAdapterConfig = serverCfg.getServantAdapterConfMap().get(homeName);
+
+ ServantAdapter ServerAdapter = new ServantAdapter(servantAdapterConfig);
+ skeleton = new ServantHomeSkeleton(homeName, homeClassImpl, homeApiClazz, codecClazz, processorClazz, maxLoadLimit);
+ skeleton.setAppContext(this);
+ ServerAdapter.bind(skeleton);
+ servantAdapterMap.put(homeName, ServerAdapter);
+ return skeleton;
+ }
+
+ private String getChildNodeValue(XMLConfigElement element, String nodeName) {
+ if (element == null) return null;
+
+ XMLConfigElement childElement = element.getChildByName(nodeName);
+
+ if (childElement == null) return null;
+
+ return StringUtils.trim(childElement.getContent());
+ }
+
+}
diff --git a/java/core/src/main/java/com/qq/tars/server/core/Adapter.java b/java/core/src/main/java/com/qq/tars/server/core/Adapter.java
new file mode 100644
index 000000000..60c3c1cd5
--- /dev/null
+++ b/java/core/src/main/java/com/qq/tars/server/core/Adapter.java
@@ -0,0 +1,22 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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.qq.tars.server.core;
+
+public interface Adapter {
+ public void bind(AppService appService) throws Exception;
+ public void stop();
+}
diff --git a/java/core/src/main/java/com/qq/tars/server/core/AppContainer.java b/java/core/src/main/java/com/qq/tars/server/core/AppContainer.java
index e80f25686..4a5ae484b 100644
--- a/java/core/src/main/java/com/qq/tars/server/core/AppContainer.java
+++ b/java/core/src/main/java/com/qq/tars/server/core/AppContainer.java
@@ -18,13 +18,16 @@
import java.io.File;
import java.io.FileFilter;
+import java.lang.reflect.Constructor;
+import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import com.qq.tars.common.support.ClassLoaderManager;
-import com.qq.tars.server.apps.AppContext;
+import com.qq.tars.rpc.exc.TarsException;
+import com.qq.tars.server.apps.AppContextImpl;
+import com.qq.tars.server.apps.XmlAppContext;
import com.qq.tars.server.config.ConfigurationManager;
-@Deprecated
public class AppContainer implements Container {
AppContext defaultApp = null;
@@ -32,7 +35,7 @@ public class AppContainer implements Container {
private final ConcurrentHashMap contexts = new ConcurrentHashMap();
public void start() throws Exception {
- loadApps();
+ loadApp();
defaultApp = contexts.get("");
System.out.println("[SERVER] The container started successfully.");
}
@@ -42,6 +45,28 @@ public void stop() throws Exception {
System.out.println("[SERVER] The container stopped successfully.");
}
+ private void loadApp() throws Exception {
+ String root = ConfigurationManager.getInstance().getServerConfig().getBasePath();
+ File path = new File(root);
+ AppContext context = null;
+
+ URL servantXML = getClass().getClassLoader().getResource("servants.xml");
+ if (servantXML != null) {
+ context = new XmlAppContext(new File(servantXML.toURI()));
+ } else if (getClass().getClassLoader().getResource("servants-spring.xml") != null){
+ System.out.println("[SERVER] find servants-spring.xml, use Spring mode.");
+ Class clazz = Class.forName("com.qq.tars.server.apps.SpringAppContext");
+ Constructor constructor = clazz.getConstructor(File.class);
+ context = (AppContext) constructor.newInstance(path);
+ } else {
+ System.out.println("[SERVER] servants profile does not exist, start failed.");
+ throw new TarsException("servants profile does not exist");
+ }
+
+ contexts.put("", context);
+ }
+
+ @Deprecated
public void loadApps() throws Exception {
String root = ConfigurationManager.getInstance().getServerConfig().getBasePath();
File dirs = new File(root + "/apps");
@@ -55,7 +80,7 @@ public boolean accept(File path) {
name = "";
}
if (path.isDirectory()) {
- AppContext context = new AppContext(name, path);
+ AppContextImpl context = new AppContextImpl(name, path);
contexts.put(name, context);
manager.registerClassLoader(name, context.getAppContextClassLoader());
}
diff --git a/java/core/src/main/java/com/qq/tars/server/core/AppContext.java b/java/core/src/main/java/com/qq/tars/server/core/AppContext.java
index 6db02ef20..24dd5ef63 100644
--- a/java/core/src/main/java/com/qq/tars/server/core/AppContext.java
+++ b/java/core/src/main/java/com/qq/tars/server/core/AppContext.java
@@ -23,4 +23,7 @@ public interface AppContext {
public abstract String name();
public void stop();
+
+ public ServantHomeSkeleton getCapHomeSkeleton(String homeName);
}
+
diff --git a/java/core/src/main/java/com/qq/tars/server/core/AsyncContext.java b/java/core/src/main/java/com/qq/tars/server/core/AsyncContext.java
index c04857407..43abd4fcc 100644
--- a/java/core/src/main/java/com/qq/tars/server/core/AsyncContext.java
+++ b/java/core/src/main/java/com/qq/tars/server/core/AsyncContext.java
@@ -47,7 +47,7 @@ private AsyncContext(Context context) {
}
private ServantHomeSkeleton getCapHomeSkeleton() {
- AppContextImpl appContext = container.getDefaultAppContext();
+ AppContext appContext = container.getDefaultAppContext();
return appContext.getCapHomeSkeleton(this.context.request().getServantName());
}
diff --git a/java/core/src/main/java/com/qq/tars/server/core/ServantAdapter.java b/java/core/src/main/java/com/qq/tars/server/core/ServantAdapter.java
index ffb2cc7a7..f952b1d87 100644
--- a/java/core/src/main/java/com/qq/tars/server/core/ServantAdapter.java
+++ b/java/core/src/main/java/com/qq/tars/server/core/ServantAdapter.java
@@ -38,7 +38,7 @@
import com.qq.tars.server.config.ServantAdapterConfig;
import com.qq.tars.server.config.ServerConfig;
-public class ServantAdapter {
+public class ServantAdapter implements Adapter {
private SelectorManager selectorManager = null;
@@ -50,8 +50,8 @@ public ServantAdapter(ServantAdapterConfig servantAdapterConfig) {
this.servantAdapterConfig = servantAdapterConfig;
}
- public void bind(ServantHomeSkeleton skeleton) throws IOException {
- this.skeleton = skeleton;
+ public void bind(AppService appService) throws IOException {
+ this.skeleton = (ServantHomeSkeleton) appService;
ServerConfig serverCfg = ConfigurationManager.getInstance().getServerConfig();
boolean keepAlive = true;
diff --git a/java/core/src/main/java/com/qq/tars/server/core/ServantHomeSkeleton.java b/java/core/src/main/java/com/qq/tars/server/core/ServantHomeSkeleton.java
index c284574b2..b38c55e3d 100644
--- a/java/core/src/main/java/com/qq/tars/server/core/ServantHomeSkeleton.java
+++ b/java/core/src/main/java/com/qq/tars/server/core/ServantHomeSkeleton.java
@@ -110,13 +110,13 @@ public Class extends Codec> getCodecClass() {
return codecClazz;
}
- private AppContextImpl appContext;
+ private AppContext appContext;
- public void setAppContext(AppContextImpl context) {
+ public void setAppContext(AppContext context) {
appContext = context;
}
- public AppContextImpl getAppContext() {
+ public AppContext getAppContext() {
return appContext;
}
}
diff --git a/java/core/src/main/java/com/qq/tars/server/core/TarsServantProcessor.java b/java/core/src/main/java/com/qq/tars/server/core/TarsServantProcessor.java
index 787dff8ab..4e7ca1c6d 100644
--- a/java/core/src/main/java/com/qq/tars/server/core/TarsServantProcessor.java
+++ b/java/core/src/main/java/com/qq/tars/server/core/TarsServantProcessor.java
@@ -86,7 +86,7 @@ public Response process(Request req, Session session) {
context.setAttribute(Context.INTERNAL_SERVICE_NAME, request.getServantName());
context.setAttribute(Context.INTERNAL_METHOD_NAME, request.getFunctionName());
context.setAttribute(Context.INTERNAL_SESSION_DATA, session);
-
+
DistributedContext distributedContext = DistributedContextManager.getDistributedContext();
distributedContext.put(DyeingSwitch.REQ, request);
distributedContext.put(DyeingSwitch.RES, response);
@@ -216,7 +216,7 @@ private TarsServantResponse createResponse(TarsServantRequest request, Session s
response.setContext(request.getContext());
return response;
}
-
+
public void preInvokeSkeleton() {
DistributedContext distributedContext = DistributedContextManager.getDistributedContext();
Request request = distributedContext.get(DyeingSwitch.REQ);
@@ -230,7 +230,7 @@ public void postInvokeSkeleton() {
DistributedContext distributedContext = DistributedContextManager.getDistributedContext();
distributedContext.clear();
}
-
+
private void initDyeing(TarsServantRequest request) {
String routeKey;
String fileName;
diff --git a/java/core/src/main/java/com/qq/tars/support/query/QueryHelper.java b/java/core/src/main/java/com/qq/tars/support/query/QueryHelper.java
index c2516701e..425b225f9 100644
--- a/java/core/src/main/java/com/qq/tars/support/query/QueryHelper.java
+++ b/java/core/src/main/java/com/qq/tars/support/query/QueryHelper.java
@@ -86,10 +86,14 @@ private String toFormatString(EndpointF endpointF, boolean active) {
value.append("-p").append(" ").append(endpointF.port).append(" ");
value.append("-t").append(" 3000 ");
value.append("-a").append(" ").append(active ? "1" : "0").append(" ");
- value.append("-g").append(" ").append(endpointF.grid);
+ value.append("-g").append(" ").append(endpointF.grid).append(" ");
if (endpointF.setId != null && endpointF.setId.length() > 0) {
value.append(" ").append("-s").append(" ").append(endpointF.setId);
}
+ if (endpointF.weightType != 0) {
+ value.append(" ").append("-v").append(" ").append(endpointF.weightType);
+ value.append(" ").append("-w").append(" ").append(endpointF.weight);
+ }
}
return value.toString();
}
diff --git a/java/net/pom.xml b/java/net/pom.xml
index 444f2ffee..68ba75bb6 100644
--- a/java/net/pom.xml
+++ b/java/net/pom.xml
@@ -6,7 +6,7 @@
qq-cloud-central
tars-parent
- 1.0.2
+ 1.0.3
tars-net
jar
diff --git a/java/pom.xml b/java/pom.xml
index 9e66aec0f..0ef680479 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -3,7 +3,7 @@
4.0.0
qq-cloud-central
tars-parent
- 1.0.2
+ 1.0.3
pom
Tars
Super POM For Projects
@@ -14,6 +14,7 @@
core
tools
protobuf
+ spring
diff --git a/java/protobuf/pom.xml b/java/protobuf/pom.xml
index 7e209dc7f..2fb36d19a 100644
--- a/java/protobuf/pom.xml
+++ b/java/protobuf/pom.xml
@@ -5,7 +5,7 @@
tars-parent
qq-cloud-central
- 1.0.2
+ 1.0.3
4.0.0
diff --git a/java/spring/pom.xml b/java/spring/pom.xml
new file mode 100644
index 000000000..bfaf35d00
--- /dev/null
+++ b/java/spring/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+ tars-parent
+ qq-cloud-central
+ 1.0.3
+
+ 4.0.0
+
+ tars-spring
+ jar
+ ${project.artifactId}
+
+
+ 4.2.9.RELEASE
+
+
+
+
+ qq-cloud-central
+ tars-core
+ ${project.parent.version}
+
+
+ org.springframework
+ spring-core
+ ${spring.version}
+
+
+ org.springframework
+ spring-context
+ ${spring.version}
+
+
+ junit
+ junit
+ 4.12
+
+
+
\ No newline at end of file
diff --git a/java/spring/src/main/java/com/qq/tars/server/apps/RestService.java b/java/spring/src/main/java/com/qq/tars/server/apps/RestService.java
new file mode 100644
index 000000000..6883513af
--- /dev/null
+++ b/java/spring/src/main/java/com/qq/tars/server/apps/RestService.java
@@ -0,0 +1,73 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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.qq.tars.server.apps;
+
+import com.qq.tars.server.core.AppContext;
+import com.qq.tars.server.core.AppService;
+import org.springframework.context.ApplicationContext;
+
+public class RestService extends AppService {
+ private AppContext appContext;
+ private String source;
+ private ApplicationContext parent;
+ private String name;
+
+ RestService(String name, String source, ApplicationContext parent) {
+ this.name = name;
+ this.source = source;
+ this.parent = parent;
+ }
+
+
+ public void setAppContext(AppContext appContext) {
+ this.appContext = appContext;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public ApplicationContext getParent() {
+ return parent;
+ }
+
+ public void setParent(ApplicationContext parent) {
+ this.parent = parent;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public AppContext getAppContext() {
+ return appContext;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+}
diff --git a/java/spring/src/main/java/com/qq/tars/server/apps/SpringAppContext.java b/java/spring/src/main/java/com/qq/tars/server/apps/SpringAppContext.java
new file mode 100644
index 000000000..6b0437262
--- /dev/null
+++ b/java/spring/src/main/java/com/qq/tars/server/apps/SpringAppContext.java
@@ -0,0 +1,160 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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.qq.tars.server.apps;
+
+import com.qq.tars.common.util.StringUtils;
+import com.qq.tars.net.core.Processor;
+import com.qq.tars.protocol.annotation.Servant;
+import com.qq.tars.protocol.util.TarsHelper;
+import com.qq.tars.rpc.protocol.Codec;
+import com.qq.tars.server.config.ConfigurationManager;
+import com.qq.tars.server.config.ServantAdapterConfig;
+import com.qq.tars.server.config.ServerConfig;
+import com.qq.tars.server.core.*;
+import com.qq.tars.server.core.AppContext;
+import com.qq.tars.support.spring.ListenerConfig;
+import com.qq.tars.support.spring.ServantConfig;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.util.Map;
+
+public class SpringAppContext extends BaseAppContext {
+ private ApplicationContext applicationContext = null;
+ public SpringAppContext(File path) {
+ super(path);
+ try {
+ initFromConfigFile();
+ injectAdminServant();
+ initServants();
+ appContextStarted();
+ System.out.println("[SERVER] The application started successfully. {appname=}");
+ } catch (Exception ex) {
+ ready = false;
+ System.err.println("[SERVER] failed to start the applicaton. {appname=}");
+ ex.printStackTrace();
+ }
+ }
+
+ private void initFromConfigFile() {
+ this.applicationContext = new ClassPathXmlApplicationContext("servants-spring.xml");
+
+ loadAppContextListeners(this.applicationContext);
+ loadAppServants(this.applicationContext);
+ }
+
+ private void loadAppContextListeners(ApplicationContext applicationContext) {
+ Map servantMap = applicationContext.getBeansOfType(ListenerConfig.class);
+ for (Map.Entry entry : servantMap.entrySet()) {
+ AppContextListener listener;
+
+ listener = (AppContextListener) applicationContext.getBean(entry.getValue().getRef());
+ listeners.add(listener);
+ }
+ }
+
+ private void loadAppServants(ApplicationContext applicationContext) {
+ Map servantMap = applicationContext.getBeansOfType(ServantConfig.class);
+ for (Map.Entry entry : servantMap.entrySet()) {
+ if (StringUtils.isEmpty(entry.getValue().getProtocol()) || !entry.getValue().getProtocol().equals("rest")) {
+ try {
+ ServantHomeSkeleton skeleton = loadServant(entry.getValue());
+ skeletonMap.put(skeleton.name(), skeleton);
+ appServantStarted(skeleton);
+ } catch (Exception e) {
+ System.err.println("init a service failed");
+ e.printStackTrace();
+ }
+ } else {
+ try {
+ AppService appService = loadRestServant(entry.getValue());
+ appServantStarted(appService);
+ } catch (Exception e) {
+ System.err.println("init a service failed");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ private AppService loadRestServant(ServantConfig servantConfig) throws Exception {
+ String homeName = servantConfig.getName();
+
+ ServerConfig serverCfg = ConfigurationManager.getInstance().getServerConfig();
+
+ if (StringUtils.isEmpty(homeName)) {
+ throw new RuntimeException("servant name is null.");
+ }
+ homeName = String.format("%s.%s.%s", serverCfg.getApplication(), serverCfg.getServerName(), homeName);
+
+ ServantAdapterConfig servantAdapterConfig = serverCfg.getServantAdapterConfMap().get(homeName);
+
+ Class clazz = Class.forName("com.qq.tars.rest.RestServantAdapter");
+ Constructor constructor = clazz.getConstructor(ServantAdapterConfig.class);
+ Adapter adapter = (Adapter) constructor.newInstance(servantAdapterConfig);
+ RestService restService = new RestService(homeName, servantConfig.getSrc(), this.applicationContext);
+ restService.setAppContext(this);
+ adapter.bind(restService);
+ servantAdapterMap.put(homeName, adapter);
+
+ return null;
+ }
+
+ private ServantHomeSkeleton loadServant(ServantConfig servantConfig) throws Exception {
+ String homeName = null, homeApiName = null;
+ Class> homeApiClazz = null;
+ Class extends Codec> codecClazz = null;
+ Class extends Processor> processorClazz = null;
+ Object homeClassImpl = null;
+ ServantHomeSkeleton skeleton = null;
+ int maxLoadLimit = -1;
+
+ ServerConfig serverCfg = ConfigurationManager.getInstance().getServerConfig();
+
+ homeName = servantConfig.getName();
+ if (StringUtils.isEmpty(homeName)) {
+ throw new RuntimeException("servant name is null.");
+ }
+ homeName = String.format("%s.%s.%s", serverCfg.getApplication(), serverCfg.getServerName(), homeName);
+ homeApiName = servantConfig.getInterface();
+
+ homeApiClazz = Class.forName(homeApiName);
+ homeClassImpl = this.applicationContext.getBean(servantConfig.getRef());
+
+ if (TarsHelper.isServant(homeApiClazz)) {
+ String servantName = homeApiClazz.getAnnotation(Servant.class).name();
+ if (!StringUtils.isEmpty(servantName) && servantName.matches("^[\\w]+\\.[\\w]+\\.[\\w]+$")) {
+ homeName = servantName;
+ }
+ }
+
+ ServantAdapterConfig servantAdapterConfig = serverCfg.getServantAdapterConfMap().get(homeName);
+
+ ServantAdapter ServerAdapter = new ServantAdapter(servantAdapterConfig);
+ skeleton = new ServantHomeSkeleton(homeName, homeClassImpl, homeApiClazz, codecClazz, processorClazz, maxLoadLimit);
+ skeleton.setAppContext(this);
+ ServerAdapter.bind(skeleton);
+ servantAdapterMap.put(homeName, ServerAdapter);
+ return skeleton;
+ }
+
+ public ApplicationContext getApplicationContext() {
+ return this.applicationContext;
+ }
+}
diff --git a/java/spring/src/main/java/com/qq/tars/support/spring/ListenerConfig.java b/java/spring/src/main/java/com/qq/tars/support/spring/ListenerConfig.java
new file mode 100644
index 000000000..b45b86ab7
--- /dev/null
+++ b/java/spring/src/main/java/com/qq/tars/support/spring/ListenerConfig.java
@@ -0,0 +1,29 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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.qq.tars.support.spring;
+
+public class ListenerConfig {
+ private String ref;
+
+ public String getRef() {
+ return ref;
+ }
+
+ public void setRef(String ref) {
+ this.ref = ref;
+ }
+}
diff --git a/java/spring/src/main/java/com/qq/tars/support/spring/ServantConfig.java b/java/spring/src/main/java/com/qq/tars/support/spring/ServantConfig.java
new file mode 100644
index 000000000..4220ae6a7
--- /dev/null
+++ b/java/spring/src/main/java/com/qq/tars/support/spring/ServantConfig.java
@@ -0,0 +1,67 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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.qq.tars.support.spring;
+
+public class ServantConfig {
+ private String name;
+ private String apiClass;
+ private String protocol;
+ private String ref;
+ private String src;
+
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getInterface() {
+ return apiClass;
+ }
+
+ public void setInterface(String apiClass) {
+ this.apiClass = apiClass;
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ public String getRef() {
+ return ref;
+ }
+
+ public void setRef(String ref) {
+ this.ref = ref;
+ }
+
+ public String getSrc() {
+ return src;
+ }
+
+ public void setSrc(String src) {
+ this.src = src;
+ }
+
+}
diff --git a/java/spring/src/main/java/com/qq/tars/support/spring/exc/TarsSpringConfigException.java b/java/spring/src/main/java/com/qq/tars/support/spring/exc/TarsSpringConfigException.java
new file mode 100644
index 000000000..f42762074
--- /dev/null
+++ b/java/spring/src/main/java/com/qq/tars/support/spring/exc/TarsSpringConfigException.java
@@ -0,0 +1,23 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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.qq.tars.support.spring.exc;
+
+public class TarsSpringConfigException extends RuntimeException {
+ public TarsSpringConfigException(String string) {
+ super(string);
+ }
+}
diff --git a/java/spring/src/main/java/com/qq/tars/support/spring/schema/TarsBeanDefinitionParser.java b/java/spring/src/main/java/com/qq/tars/support/spring/schema/TarsBeanDefinitionParser.java
new file mode 100644
index 000000000..375be81a7
--- /dev/null
+++ b/java/spring/src/main/java/com/qq/tars/support/spring/schema/TarsBeanDefinitionParser.java
@@ -0,0 +1,86 @@
+/**
+ * Tencent is pleased to support the open source community by making Tars available.
+ *
+ * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
+ *
+ * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ *
+ * 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.qq.tars.support.spring.schema;
+
+import com.qq.tars.support.spring.ListenerConfig;
+import com.qq.tars.support.spring.ServantConfig;
+import com.qq.tars.support.spring.exc.TarsSpringConfigException;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+public class TarsBeanDefinitionParser implements BeanDefinitionParser {
+
+ private Class> clssze;
+
+ TarsBeanDefinitionParser(Class> cls) {
+ this.clssze = cls;
+ }
+
+ @Override
+ public BeanDefinition parse(Element element, ParserContext parserContext) {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition();
+ beanDefinition.setBeanClass(clssze);
+ String id = null;
+ id = element.getAttribute("name");
+ if (id == null || id.length() == 0) {
+ if (clssze == ServantConfig.class) {
+ throw new TarsSpringConfigException("Messing servant name");
+ } else if (clssze == ListenerConfig.class) {
+ id = "listener";
+
+ int counter = 0;
+ while(parserContext.getRegistry().containsBeanDefinition(id + counter)) {
+ counter++;
+ }
+
+ id = id + counter;
+ }
+ }
+
+
+ if (id != null && id.length() > 0) {
+ if(parserContext.getRegistry().containsBeanDefinition(id)) {
+ throw new TarsSpringConfigException("Duplicate spring bean id " + id);
+ }
+ parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
+ }
+
+ NamedNodeMap nnm =element.getAttributes();
+ for (int i = 0; i
qq-cloud-central
tars-parent
- 1.0.2
+ 1.0.3
tars-tools
${project.artifactId}