Created
August 22, 2014 02:58
-
-
Save diegozeng/b8bf17b88caedb74e615 to your computer and use it in GitHub Desktop.
Dubbo框架中利用ReferenceConfig类的init方法调用Protocol(Dubbo/Hessian/Injvm/Rmi/Webservice)的refer方法生成Invoker实例.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright 1999-2011 Alibaba Group. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package com.alibaba.dubbo.config; | |
| import java.io.File; | |
| import java.io.FileInputStream; | |
| import java.io.IOException; | |
| import java.lang.reflect.Method; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.HashMap; | |
| import java.util.HashSet; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.Properties; | |
| import com.alibaba.dubbo.common.Constants; | |
| import com.alibaba.dubbo.common.URL; | |
| import com.alibaba.dubbo.common.Version; | |
| import com.alibaba.dubbo.common.bytecode.Wrapper; | |
| import com.alibaba.dubbo.common.extension.ExtensionLoader; | |
| import com.alibaba.dubbo.common.utils.ConfigUtils; | |
| import com.alibaba.dubbo.common.utils.NetUtils; | |
| import com.alibaba.dubbo.common.utils.ReflectUtils; | |
| import com.alibaba.dubbo.common.utils.StringUtils; | |
| import com.alibaba.dubbo.config.annotation.Reference; | |
| import com.alibaba.dubbo.config.support.Parameter; | |
| import com.alibaba.dubbo.rpc.Invoker; | |
| import com.alibaba.dubbo.rpc.Protocol; | |
| import com.alibaba.dubbo.rpc.ProxyFactory; | |
| import com.alibaba.dubbo.rpc.StaticContext; | |
| import com.alibaba.dubbo.rpc.cluster.Cluster; | |
| import com.alibaba.dubbo.rpc.cluster.directory.StaticDirectory; | |
| import com.alibaba.dubbo.rpc.cluster.support.AvailableCluster; | |
| import com.alibaba.dubbo.rpc.cluster.support.ClusterUtils; | |
| import com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol; | |
| import com.alibaba.dubbo.rpc.service.GenericService; | |
| import com.alibaba.dubbo.rpc.support.ProtocolUtils; | |
| /** | |
| * ReferenceConfig | |
| * | |
| * @author william.liangf | |
| * @export | |
| */ | |
| public class ReferenceConfig<T> extends AbstractReferenceConfig { | |
| private static final long serialVersionUID = -5864351140409987595L; | |
| private static final Protocol refprotocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension(); | |
| private static final Cluster cluster = ExtensionLoader.getExtensionLoader(Cluster.class).getAdaptiveExtension(); | |
| private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension(); | |
| // 鎺ュ彛绫诲瀷 | |
| private String interfaceName; | |
| private Class<?> interfaceClass; | |
| // 瀹㈡埛绔被鍨� | |
| private String client; | |
| // 鐐瑰鐐圭洿杩炴湇鍔℃彁渚涘湴鍧� | |
| private String url; | |
| // 鏂规硶閰嶇疆 | |
| private List<MethodConfig> methods; | |
| // 缂虹渷閰嶇疆 | |
| private ConsumerConfig consumer; | |
| private String protocol; | |
| // 鎺ュ彛浠g悊绫诲紩鐢� | |
| private transient volatile T ref; | |
| private transient volatile Invoker<?> invoker; | |
| private transient volatile boolean initialized; | |
| private transient volatile boolean destroyed; | |
| private final List<URL> urls = new ArrayList<URL>(); | |
| @SuppressWarnings("unused") | |
| private final Object finalizerGuardian = new Object() { | |
| @Override | |
| protected void finalize() throws Throwable { | |
| super.finalize(); | |
| if(! ReferenceConfig.this.destroyed) { | |
| logger.warn("ReferenceConfig(" + url + ") is not DESTROYED when FINALIZE"); | |
| /* 鍏堜笉鍋欴estroy鎿嶄綔 | |
| try { | |
| ReferenceConfig.this.destroy(); | |
| } catch (Throwable t) { | |
| logger.warn("Unexpected err when destroy invoker of ReferenceConfig(" + url + ") in finalize method!", t); | |
| } | |
| */ | |
| } | |
| } | |
| }; | |
| public ReferenceConfig() {} | |
| public ReferenceConfig(Reference reference) { | |
| appendAnnotation(Reference.class, reference); | |
| } | |
| public URL toUrl() { | |
| return urls == null || urls.size() == 0 ? null : urls.iterator().next(); | |
| } | |
| public List<URL> toUrls() { | |
| return urls; | |
| } | |
| public synchronized T get() { | |
| if (destroyed){ | |
| throw new IllegalStateException("Already destroyed!"); | |
| } | |
| if (ref == null) { | |
| init(); | |
| } | |
| return ref; | |
| } | |
| public synchronized void destroy() { | |
| if (ref == null) { | |
| return; | |
| } | |
| if (destroyed){ | |
| return; | |
| } | |
| destroyed = true; | |
| try { | |
| invoker.destroy(); | |
| } catch (Throwable t) { | |
| logger.warn("Unexpected err when destroy invoker of ReferenceConfig(" + url + ").", t); | |
| } | |
| invoker = null; | |
| ref = null; | |
| } | |
| private void init() { | |
| if (initialized) { | |
| return; | |
| } | |
| initialized = true; | |
| if (interfaceName == null || interfaceName.length() == 0) { | |
| throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!"); | |
| } | |
| // 鑾峰彇娑堣垂鑰呭叏灞�厤缃� | |
| checkDefault(); | |
| appendProperties(this); | |
| if (getGeneric() == null && getConsumer() != null) { | |
| setGeneric(getConsumer().getGeneric()); | |
| } | |
| if (ProtocolUtils.isGeneric(getGeneric())) { | |
| interfaceClass = GenericService.class; | |
| } else { | |
| try { | |
| interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() | |
| .getContextClassLoader()); | |
| } catch (ClassNotFoundException e) { | |
| throw new IllegalStateException(e.getMessage(), e); | |
| } | |
| checkInterfaceAndMethods(interfaceClass, methods); | |
| } | |
| String resolve = System.getProperty(interfaceName); | |
| String resolveFile = null; | |
| if (resolve == null || resolve.length() == 0) { | |
| resolveFile = System.getProperty("dubbo.resolve.file"); | |
| if (resolveFile == null || resolveFile.length() == 0) { | |
| File userResolveFile = new File(new File(System.getProperty("user.home")), "dubbo-resolve.properties"); | |
| if (userResolveFile.exists()) { | |
| resolveFile = userResolveFile.getAbsolutePath(); | |
| } | |
| } | |
| if (resolveFile != null && resolveFile.length() > 0) { | |
| Properties properties = new Properties(); | |
| FileInputStream fis = null; | |
| try { | |
| fis = new FileInputStream(new File(resolveFile)); | |
| properties.load(fis); | |
| } catch (IOException e) { | |
| throw new IllegalStateException("Unload " + resolveFile + ", cause: " + e.getMessage(), e); | |
| } finally { | |
| try { | |
| if(null != fis) fis.close(); | |
| } catch (IOException e) { | |
| logger.warn(e.getMessage(), e); | |
| } | |
| } | |
| resolve = properties.getProperty(interfaceName); | |
| } | |
| } | |
| if (resolve != null && resolve.length() > 0) { | |
| url = resolve; | |
| if (logger.isWarnEnabled()) { | |
| if (resolveFile != null && resolveFile.length() > 0) { | |
| logger.warn("Using default dubbo resolve file " + resolveFile + " replace " + interfaceName + "" + resolve + " to p2p invoke remote service."); | |
| } else { | |
| logger.warn("Using -D" + interfaceName + "=" + resolve + " to p2p invoke remote service."); | |
| } | |
| } | |
| } | |
| if (consumer != null) { | |
| if (application == null) { | |
| application = consumer.getApplication(); | |
| } | |
| if (module == null) { | |
| module = consumer.getModule(); | |
| } | |
| if (registries == null) { | |
| registries = consumer.getRegistries(); | |
| } | |
| if (monitor == null) { | |
| monitor = consumer.getMonitor(); | |
| } | |
| } | |
| if (module != null) { | |
| if (registries == null) { | |
| registries = module.getRegistries(); | |
| } | |
| if (monitor == null) { | |
| monitor = module.getMonitor(); | |
| } | |
| } | |
| if (application != null) { | |
| if (registries == null) { | |
| registries = application.getRegistries(); | |
| } | |
| if (monitor == null) { | |
| monitor = application.getMonitor(); | |
| } | |
| } | |
| checkApplication(); | |
| checkStubAndMock(interfaceClass); | |
| Map<String, String> map = new HashMap<String, String>(); | |
| Map<Object, Object> attributes = new HashMap<Object, Object>(); | |
| map.put(Constants.SIDE_KEY, Constants.CONSUMER_SIDE); | |
| map.put(Constants.DUBBO_VERSION_KEY, Version.getVersion()); | |
| map.put(Constants.TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis())); | |
| if (ConfigUtils.getPid() > 0) { | |
| map.put(Constants.PID_KEY, String.valueOf(ConfigUtils.getPid())); | |
| } | |
| if (! isGeneric()) { | |
| String revision = Version.getVersion(interfaceClass, version); | |
| if (revision != null && revision.length() > 0) { | |
| map.put("revision", revision); | |
| } | |
| String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); | |
| if(methods.length == 0) { | |
| logger.warn("NO method found in service interface " + interfaceClass.getName()); | |
| map.put("methods", Constants.ANY_VALUE); | |
| } | |
| else { | |
| map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ",")); | |
| } | |
| } | |
| map.put(Constants.INTERFACE_KEY, interfaceName); | |
| appendParameters(map, application); | |
| appendParameters(map, module); | |
| appendParameters(map, consumer, Constants.DEFAULT_KEY); | |
| appendParameters(map, this); | |
| String prifix = StringUtils.getServiceKey(map); | |
| if (methods != null && methods.size() > 0) { | |
| for (MethodConfig method : methods) { | |
| appendParameters(map, method, method.getName()); | |
| String retryKey = method.getName() + ".retry"; | |
| if (map.containsKey(retryKey)) { | |
| String retryValue = map.remove(retryKey); | |
| if ("false".equals(retryValue)) { | |
| map.put(method.getName() + ".retries", "0"); | |
| } | |
| } | |
| appendAttributes(attributes, method, prifix + "." + method.getName()); | |
| checkAndConvertImplicitConfig(method, map, attributes); | |
| } | |
| } | |
| //attributes閫氳繃绯荤粺context杩涜瀛樺偍. | |
| StaticContext.getSystemContext().putAll(attributes); | |
| ref = createProxy(map); | |
| } | |
| private static void checkAndConvertImplicitConfig(MethodConfig method, Map<String,String> map, Map<Object,Object> attributes){ | |
| //check config conflict | |
| if (Boolean.FALSE.equals(method.isReturn()) && (method.getOnreturn() != null || method.getOnthrow() != null)) { | |
| throw new IllegalStateException("method config error : return attribute must be set true when onreturn or onthrow has been setted."); | |
| } | |
| //convert onreturn methodName to Method | |
| String onReturnMethodKey = StaticContext.getKey(map,method.getName(),Constants.ON_RETURN_METHOD_KEY); | |
| Object onReturnMethod = attributes.get(onReturnMethodKey); | |
| if (onReturnMethod != null && onReturnMethod instanceof String){ | |
| attributes.put(onReturnMethodKey, getMethodByName(method.getOnreturn().getClass(), onReturnMethod.toString())); | |
| } | |
| //convert onthrow methodName to Method | |
| String onThrowMethodKey = StaticContext.getKey(map,method.getName(),Constants.ON_THROW_METHOD_KEY); | |
| Object onThrowMethod = attributes.get(onThrowMethodKey); | |
| if (onThrowMethod != null && onThrowMethod instanceof String){ | |
| attributes.put(onThrowMethodKey, getMethodByName(method.getOnthrow().getClass(), onThrowMethod.toString())); | |
| } | |
| //convert oninvoke methodName to Method | |
| String onInvokeMethodKey = StaticContext.getKey(map,method.getName(),Constants.ON_INVOKE_METHOD_KEY); | |
| Object onInvokeMethod = attributes.get(onInvokeMethodKey); | |
| if (onInvokeMethod != null && onInvokeMethod instanceof String){ | |
| attributes.put(onInvokeMethodKey, getMethodByName(method.getOninvoke().getClass(), onInvokeMethod.toString())); | |
| } | |
| } | |
| private static Method getMethodByName(Class<?> clazz, String methodName){ | |
| try { | |
| return ReflectUtils.findMethodByMethodName(clazz, methodName); | |
| } catch (Exception e) { | |
| throw new IllegalStateException(e); | |
| } | |
| } | |
| @SuppressWarnings({ "unchecked", "rawtypes", "deprecation" }) | |
| private T createProxy(Map<String, String> map) { | |
| URL tmpUrl = new URL("temp", "localhost", 0, map); | |
| final boolean isJvmRefer; | |
| if (isInjvm() == null) { | |
| if (url != null && url.length() > 0) { //鎸囧畾URL鐨勬儏鍐典笅锛屼笉鍋氭湰鍦板紩鐢� | |
| isJvmRefer = false; | |
| } else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) { | |
| //榛樿鎯呭喌涓嬪鏋滄湰鍦版湁鏈嶅姟鏆撮湶锛屽垯寮曠敤鏈湴鏈嶅姟. | |
| isJvmRefer = true; | |
| } else { | |
| isJvmRefer = false; | |
| } | |
| } else { | |
| isJvmRefer = isInjvm().booleanValue(); | |
| } | |
| if (isJvmRefer) { | |
| URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map); | |
| invoker = refprotocol.refer(interfaceClass, url); | |
| if (logger.isInfoEnabled()) { | |
| logger.info("Using injvm service " + interfaceClass.getName()); | |
| } | |
| } else { | |
| if (url != null && url.length() > 0) { // 鐢ㄦ埛鎸囧畾URL锛屾寚瀹氱殑URL鍙兘鏄鐐瑰鐩磋繛鍦板潃锛屼篃鍙兘鏄敞鍐屼腑蹇僓RL | |
| String[] us = Constants.SEMICOLON_SPLIT_PATTERN.split(url); | |
| if (us != null && us.length > 0) { | |
| for (String u : us) { | |
| URL url = URL.valueOf(u); | |
| if (url.getPath() == null || url.getPath().length() == 0) { | |
| url = url.setPath(interfaceName); | |
| } | |
| if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { | |
| urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map))); | |
| } else { | |
| urls.add(ClusterUtils.mergeUrl(url, map)); | |
| } | |
| } | |
| } | |
| } else { // 閫氳繃娉ㄥ唽涓績閰嶇疆鎷艰URL | |
| List<URL> us = loadRegistries(false); | |
| if (us != null && us.size() > 0) { | |
| for (URL u : us) { | |
| URL monitorUrl = loadMonitor(u); | |
| if (monitorUrl != null) { | |
| map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString())); | |
| } | |
| urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map))); | |
| } | |
| } | |
| if (urls == null || urls.size() == 0) { | |
| throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address=\"...\" /> to your spring config."); | |
| } | |
| } | |
| if (urls.size() == 1) { | |
| invoker = refprotocol.refer(interfaceClass, urls.get(0)); | |
| } else { | |
| List<Invoker<?>> invokers = new ArrayList<Invoker<?>>(); | |
| URL registryURL = null; | |
| for (URL url : urls) { | |
| invokers.add(refprotocol.refer(interfaceClass, url)); | |
| if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { | |
| registryURL = url; // 鐢ㄤ簡鏈�悗涓�釜registry url | |
| } | |
| } | |
| if (registryURL != null) { // 鏈�娉ㄥ唽涓績鍗忚鐨刄RL | |
| // 瀵规湁娉ㄥ唽涓績鐨凜luster 鍙敤 AvailableCluster | |
| URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME); | |
| invoker = cluster.join(new StaticDirectory(u, invokers)); | |
| } else { // 涓嶆槸 娉ㄥ唽涓績鐨刄RL | |
| invoker = cluster.join(new StaticDirectory(invokers)); | |
| } | |
| } | |
| } | |
| Boolean c = check; | |
| if (c == null && consumer != null) { | |
| c = consumer.isCheck(); | |
| } | |
| if (c == null) { | |
| c = true; // default true | |
| } | |
| if (c && ! invoker.isAvailable()) { | |
| throw new IllegalStateException("Failed to check the status of the service " + interfaceName + ". No provider available for the service " + (group == null ? "" : group + "/") + interfaceName + (version == null ? "" : ":" + version) + " from the url " + invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion()); | |
| } | |
| if (logger.isInfoEnabled()) { | |
| logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl()); | |
| } | |
| // 鍒涘缓鏈嶅姟浠g悊 | |
| return (T) proxyFactory.getProxy(invoker); | |
| } | |
| private void checkDefault() { | |
| if (consumer == null) { | |
| consumer = new ConsumerConfig(); | |
| } | |
| appendProperties(consumer); | |
| } | |
| public Class<?> getInterfaceClass() { | |
| if (interfaceClass != null) { | |
| return interfaceClass; | |
| } | |
| if (isGeneric() | |
| || (getConsumer() != null && getConsumer().isGeneric())) { | |
| return GenericService.class; | |
| } | |
| try { | |
| if (interfaceName != null && interfaceName.length() > 0) { | |
| this.interfaceClass = Class.forName(interfaceName, true, Thread.currentThread() | |
| .getContextClassLoader()); | |
| } | |
| } catch (ClassNotFoundException t) { | |
| throw new IllegalStateException(t.getMessage(), t); | |
| } | |
| return interfaceClass; | |
| } | |
| /** | |
| * @deprecated | |
| * @see #setInterface(Class) | |
| * @param interfaceClass | |
| */ | |
| @Deprecated | |
| public void setInterfaceClass(Class<?> interfaceClass) { | |
| setInterface(interfaceClass); | |
| } | |
| public String getInterface() { | |
| return interfaceName; | |
| } | |
| public void setInterface(String interfaceName) { | |
| this.interfaceName = interfaceName; | |
| if (id == null || id.length() == 0) { | |
| id = interfaceName; | |
| } | |
| } | |
| public void setInterface(Class<?> interfaceClass) { | |
| if (interfaceClass != null && ! interfaceClass.isInterface()) { | |
| throw new IllegalStateException("The interface class " + interfaceClass + " is not a interface!"); | |
| } | |
| this.interfaceClass = interfaceClass; | |
| setInterface(interfaceClass == null ? (String) null : interfaceClass.getName()); | |
| } | |
| public String getClient() { | |
| return client; | |
| } | |
| public void setClient(String client) { | |
| checkName("client", client); | |
| this.client = client; | |
| } | |
| @Parameter(excluded = true) | |
| public String getUrl() { | |
| return url; | |
| } | |
| public void setUrl(String url) { | |
| this.url = url; | |
| } | |
| public List<MethodConfig> getMethods() { | |
| return methods; | |
| } | |
| @SuppressWarnings("unchecked") | |
| public void setMethods(List<? extends MethodConfig> methods) { | |
| this.methods = (List<MethodConfig>) methods; | |
| } | |
| public ConsumerConfig getConsumer() { | |
| return consumer; | |
| } | |
| public void setConsumer(ConsumerConfig consumer) { | |
| this.consumer = consumer; | |
| } | |
| public String getProtocol() { | |
| return protocol; | |
| } | |
| public void setProtocol(String protocol) { | |
| this.protocol = protocol; | |
| } | |
| // just for test | |
| Invoker<?> getInvoker() { | |
| return invoker; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment