From 787dae1d14e9ab541fec533a99b4f5bb64297eab Mon Sep 17 00:00:00 2001 From: yihengli Date: Fri, 1 Dec 2017 16:42:19 +0800 Subject: [PATCH] Merge remote-tracking branch 'remotes/origin/tars-java-dev' # Conflicts: # docs/README.md --- java/core/client.pom.xml | 2 +- java/core/pom.xml | 2 +- java/core/server.pom.xml | 2 +- .../java/com/qq/tars/client/Communicator.java | 4 +- .../java/com/qq/tars/client/ObjectProxy.java | 15 +- .../qq/tars/client/ObjectProxyFactory.java | 9 +- .../qq/tars/client/ServantProxyConfig.java | 30 ++++ .../client/cluster/DefaultLoadBalance.java | 3 +- .../com/qq/tars/client/util/ParseTools.java | 13 ++ .../com/qq/tars/common/util/Constants.java | 6 + .../com/qq/tars/rpc/common/LoadBalance.java | 17 +- .../com/qq/tars/server/ServerVersion.java | 2 +- .../qq/tars/server/apps/BaseAppContext.java | 122 +++++++++++++ .../qq/tars/server/apps/XmlAppContext.java | 168 ++++++++++++++++++ .../java/com/qq/tars/server/core/Adapter.java | 22 +++ .../com/qq/tars/server/core/AppContainer.java | 33 +++- .../com/qq/tars/server/core/AppContext.java | 3 + .../com/qq/tars/server/core/AsyncContext.java | 2 +- .../qq/tars/server/core/ServantAdapter.java | 6 +- .../tars/server/core/ServantHomeSkeleton.java | 6 +- .../server/core/TarsServantProcessor.java | 6 +- .../qq/tars/support/query/QueryHelper.java | 6 +- java/net/pom.xml | 2 +- java/pom.xml | 3 +- java/protobuf/pom.xml | 2 +- java/spring/pom.xml | 42 +++++ .../com/qq/tars/server/apps/RestService.java | 73 ++++++++ .../qq/tars/server/apps/SpringAppContext.java | 160 +++++++++++++++++ .../tars/support/spring/ListenerConfig.java | 29 +++ .../qq/tars/support/spring/ServantConfig.java | 67 +++++++ .../spring/exc/TarsSpringConfigException.java | 23 +++ .../schema/TarsBeanDefinitionParser.java | 86 +++++++++ .../spring/schema/TarsNamespaceHandler.java | 29 +++ .../main/resources/META-INF/spring.handlers | 2 +- java/tools/pom.xml | 2 +- 35 files changed, 962 insertions(+), 37 deletions(-) create mode 100644 java/core/src/main/java/com/qq/tars/server/apps/BaseAppContext.java create mode 100644 java/core/src/main/java/com/qq/tars/server/apps/XmlAppContext.java create mode 100644 java/core/src/main/java/com/qq/tars/server/core/Adapter.java create mode 100644 java/spring/pom.xml create mode 100644 java/spring/src/main/java/com/qq/tars/server/apps/RestService.java create mode 100644 java/spring/src/main/java/com/qq/tars/server/apps/SpringAppContext.java create mode 100644 java/spring/src/main/java/com/qq/tars/support/spring/ListenerConfig.java create mode 100644 java/spring/src/main/java/com/qq/tars/support/spring/ServantConfig.java create mode 100644 java/spring/src/main/java/com/qq/tars/support/spring/exc/TarsSpringConfigException.java create mode 100644 java/spring/src/main/java/com/qq/tars/support/spring/schema/TarsBeanDefinitionParser.java create mode 100644 java/spring/src/main/java/com/qq/tars/support/spring/schema/TarsNamespaceHandler.java 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 codecClazz = null; + Class 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) (StringUtils.isEmpty(codecClazzName) ? null : Class.forName(codecClazzName)); + processorClazz = (Class) (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 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 codecClazz = null; + Class 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}