前兩篇文章 Dubbo的服務導出1之導出到本地、Dubbo的服務導出2之導出到遠程 詳細分析了服務導出的過程,本篇文章咱們趁熱打鐵,繼續分析服務引用過程。在 Dubbo 中,咱們能夠經過兩種方式引用遠程服務。第一種是使用服務直連的方式引用服務
,第二種方式是基於註冊中心進行引用
。服務直連的方式僅適合在調試或測試服務的場景下使用,不適合在線上環境使用。所以,本文我將重點分析經過註冊中心引用服務的過程。從註冊中心中獲取服務配置只是服務引用過程當中的一環,除此以外,服務消費者還須要經歷 Invoker 建立、代理類建立等步驟。這些步驟,將在後續章節中一一進行分析。java
Dubbo 服務引用的時機有兩個,第一個是在Spring 容器調用 ReferenceBean的afterPropertiesSet方法時引用服務
,第二個是在 ReferenceBean對應的服務被注入到其餘類中時引用
。這兩個引用服務的時機區別在於,第一個是餓漢式的,第二個是懶漢式的。默認狀況下,Dubbo使用懶漢式引用服務
。若是須要使用餓漢式,可經過配置 <dubbo:reference> 的 init 屬性開啓。下面咱們按照 Dubbo 默認配置進行分析,整個分析過程從 ReferenceBean 的 getObject 方法
開始。當咱們的服務被注入到其餘類中時,Spring 會第一時間調用 getObject 方法,並由該方法執行服務引用邏輯。按照慣例,在進行具體工做以前,需先進行配置檢查與收集工做。接着根據收集到的信息決定服務用的方式,有三種,第一種是引用本地 (JVM) 服務
,第二是經過直連方式引用遠程服務
,第三是經過註冊中心引用遠程服務
。不論是哪一種引用方式,最後都會獲得一個 Invoker 實例。若是有多個註冊中心,多個服務提供者,這個時候會獲得一組 Invoker 實例,此時須要經過集羣管理類 Cluster 將多個 Invoker 合併成一個實例。合併後的 Invoker 實例已經具有調用本地或遠程服務的能力了,但並不能將此實例暴露給用戶使用,這會對用戶業務代碼形成侵入。此時框架還須要經過代理工廠類 (ProxyFactory) 爲服務接口生成代理類,並讓代理類去調用 Invoker 邏輯。避免了 Dubbo 框架代碼對業務代碼的侵入,同時也讓框架更容易使用。
以上就是服務引用的大體原理,下面咱們深刻到代碼中,詳細分析服務引用細節。apache
// ReferenceBean實現了InitializingBean接口,所以在Spring容器初始化時會調用該方法,這裏也對應上述第一個引用時機 // 默認不會走這裏的引用服務方法,須要配置init=true @Override public void afterPropertiesSet() throws Exception { // 刪除一些代碼 // Dubbo服務引用的時機有兩個,第一個是在Spring容器調用ReferenceBean的afterPropertiesSet // 方法時引用服務,第二個是在ReferenceBean對應的服務被注入到其餘類中時引用.這兩個引用服務的時機 // 區別在於,第一個是餓漢式的,第二個是懶漢式的.默認狀況下,Dubbo使用懶漢式引用服務.若是須要使用 // 餓漢式,可經過配置<dubbo:reference>的init屬性開啓. Boolean b = isInit(); if (b == null && getConsumer() != null) { b = getConsumer().isInit(); } if (b != null && b.booleanValue()) { getObject(); } }
/** * 整個分析過程從ReferenceBean的getObject方法開始.當咱們的服務被注入到其餘類中時, * Spring會第一時間調用getObject方法,並由該方法執行服務引用邏輯 */ @Override public Object getObject() throws Exception { return get(); } public synchronized T get() { if (destroyed) { throw new IllegalStateException("Already destroyed!"); } // 檢測ref是否爲空,爲空則經過init方法建立 if (ref == null) { // init方法主要用於處理配置,以及調用createProxy生成代理類 init(); } return ref; }
init方法比較長,爲了排版,分紅幾段,並刪除異常捕捉、日誌記錄等代碼,核心代碼是ref = createProxy(map)
。segmentfault
private void init() { // 避免重複初始化 if (initialized) { return; } initialized = true; // 檢查接口合法性 if (interfaceName == null || interfaceName.length() == 0) { throw new IllegalStateException("xxx"); } // 獲取consumer的全局配置 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); } // 獲取與接口名對應的配置 resolve = properties.getProperty(interfaceName); } } if (resolve != null && resolve.length() > 0) { // 將resolve賦值給url,用於點對點直連 url = resolve; }
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(); } } // 檢測Application合法性 checkApplication(); // 檢測本地存根配置合法性 checkStubAndMock(interfaceClass); // 添加side、協議版本信息、時間戳和進程號等信息到map中,side表示處於哪一側,目前是處於服務消費者側 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.getProtocolVersion()); 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); } // 獲取接口方法列表,並添加到map中 String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames(); if (methods.length == 0) { map.put("methods", Constants.ANY_VALUE); } else { map.put("methods", StringUtils.join(new HashSet<String>(Arrays.asList(methods)), ",")); } } map.put(Constants.INTERFACE_KEY, interfaceName); // 將ApplicationConfig、ConsumerConfig、ReferenceConfig等對象的字段信息添加到map中 appendParameters(map, application); appendParameters(map, module); appendParameters(map, consumer, Constants.DEFAULT_KEY); appendParameters(map, this);
// 形如com.alibaba.dubbo.demo.DemoService String prefix = StringUtils.getServiceKey(map); if (methods != null && !methods.isEmpty()) { // 遍歷MethodConfig列表 for (MethodConfig method : methods) { appendParameters(map, method, method.getName()); String retryKey = method.getName() + ".retry"; // 檢測map是否包含methodName.retry if (map.containsKey(retryKey)) { String retryValue = map.remove(retryKey); if ("false".equals(retryValue)) { // 添加劇試次數配置methodName.retries map.put(method.getName() + ".retries", "0"); } } // 添加MethodConfig中的「屬性」字段到attributes // 好比onreturn、onthrow、oninvoke等 appendAttributes(attributes, method, prefix + "." + method.getName()); checkAndConvertImplicitConfig(method, map, attributes); } }
// 獲取服務消費者ip地址 String hostToRegistry = ConfigUtils.getSystemProperty(Constants.DUBBO_IP_TO_REGISTRY); if (hostToRegistry == null || hostToRegistry.length() == 0) { hostToRegistry = NetUtils.getLocalHost(); } else if (isInvalidLocalHost(hostToRegistry)) { throw new IllegalArgumentException(""); } map.put(Constants.REGISTER_IP_KEY, hostToRegistry); // 存儲attributes到系統上下文中 StaticContext.getSystemContext().putAll(attributes); // 建立代理類,核心 ref = createProxy(map); // 根據服務名,ReferenceConfig,代理類構建ConsumerModel, // 並將ConsumerModel存入到ApplicationModel中 ConsumerModel consumerModel = new ConsumerModel(getUniqueServiceName(), this, ref, interfaceClass.getMethods()); ApplicationModel.initConsumerModel(getUniqueServiceName(), consumerModel); }
上述init()方法的核心代碼是ref = createProxy(map),下面分析這個方法。緩存
// 從字面意思上來看,createProxy彷佛只是用於建立代理對象的,但實際上並不是如此, // 該方法還會調用其餘方法構建以及合併Invoker實例 private T createProxy(Map<String, String> map) { URL tmpUrl = new URL("temp", "localhost", 0, map); final boolean isJvmRefer; if (isInjvm() == null) { // url配置被指定,則不作本地引用,我理解該url是用來作直連的 if (url != null && url.length() > 0) { isJvmRefer = false; } // 根據url的協議、scope以及injvm等參數檢測是否須要本地引用 // 好比若是用戶顯式配置了scope=local,此時isInjvmRefer返回true else if (InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) { isJvmRefer = true; } else { isJvmRefer = false; } } else { // 獲取injvm配置值 isJvmRefer = isInjvm().booleanValue(); }
// 本地引用 if (isJvmRefer) { // 生成本地引用URL,協議爲injvm URL url = new URL(Constants.LOCAL_PROTOCOL, NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map); // 調用refer方法構建InjvmInvoker實例 invoker = refprotocol.refer(interfaceClass, url); }
// 遠程引用 else { // url不爲空,代表用戶可能想進行點對點調用 if (url != null && url.length() > 0) { 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.isEmpty()) { for (URL u : us) { URL monitorUrl = loadMonitor(u); if (monitorUrl != null) { map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString())); } // 添加refer參數到url中,並將url添加到urls中 urls.add(u.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map))); } } // 未配置註冊中心,拋出異常 if (urls.isEmpty()) { // 拋異常 } }
// 單個註冊中心或服務提供者(服務直連,下同) if (urls.size() == 1) { // 1. 調用RegistryProtocol的refer構建Invoker實例,普通狀況下走這個邏輯 invoker = refprotocol.refer(interfaceClass, urls.get(0)); }
// 多個註冊中心或多個服務提供者,或者二者混合 else { List<Invoker<?>> invokers = new ArrayList<Invoker<?>>(); URL registryURL = null; for (URL url : urls) { // 獲取全部的Invoker,經過refprotocol調用refer構建Invoker,refprotocol會在運行時 // 根據url協議頭加載指定的Protocol實例,並調用實例的refer方法 invokers.add(refprotocol.refer(interfaceClass, url)); if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { registryURL = url; } } // 若是註冊中心連接不爲空,則將使用AvailableCluster if (registryURL != null) { URL u = registryURL.addParameter(Constants.CLUSTER_KEY, AvailableCluster.NAME); // 建立StaticDirectory實例,並由Cluster對多個Invoker進行合併 invoker = cluster.join(new StaticDirectory(u, invokers)); } else { invoker = cluster.join(new StaticDirectory(invokers)); } } }
Boolean c = check; if (c == null && consumer != null) { c = consumer.isCheck(); } if (c == null) { // default true c = true; } // invoker可用性檢查 if (c && !invoker.isAvailable()) { // 拋異常 } // 2. 生成代理類,核心 // Invoker建立完畢後,接下來要作的事情是爲服務接口生成代理對象.有了代理對象, // 便可進行遠程調用.代理對象生成的入口方法爲ProxyFactory的getProxy return (T) proxyFactory.getProxy(invoker); }
// 下面分析建立Invoker,單個註冊中心或服務提供者(服務直連,下同) if (urls.size() == 1) { // 1. 調用RegistryProtocol的refer構建Invoker實例,普通狀況下走這個邏輯 // 這裏實際還會先走ProtocolFilterWrapper和ProtocolListenerWrapper的refer方法,不過總的邏輯不影響 invoker = refprotocol.refer(interfaceClass, urls.get(0)); }
// ProtocolFilterWrapper public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { // 走這裏 return protocol.refer(type, url); } return buildInvokerChain(protocol.refer(type, url), Constants.REFERENCE_FILTER_KEY, Constants.CONSUMER); } // ProtocolListenerWrapper public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { // 走這裏 return protocol.refer(type, url); } return new ListenerInvokerWrapper<T>(protocol.refer(type, url), Collections.unmodifiableList( ExtensionLoader.getExtensionLoader(InvokerListener.class) .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY))); }
// 最終走到RegistryProtocol的refer方法 public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { // protocol爲zookeeper,調試加的 String protocol = url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY); url = url.setProtocol(url.getParameter(Constants.REGISTRY_KEY, Constants.DEFAULT_REGISTRY)).removeParameter(Constants.REGISTRY_KEY); // 獲取註冊中心實例 Registry registry = registryFactory.getRegistry(url); // 這裏的type是"" if (RegistryService.class.equals(type)) { return proxyFactory.getInvoker((T) registry, type, url); }
// 將url查詢字符串轉爲Map Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(Constants.REFER_KEY)); // 獲取group配置 String group = qs.get(Constants.GROUP_KEY); if (group != null && group.length() > 0) { if ((Constants.COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) { // 經過SPI加載MergeableCluster實例,並調用doRefer繼續執行服務引用邏輯 return doRefer(getMergeableCluster(), registry, type, url); } } // 調用doRefer繼續執行服務引用邏輯 return doRefer(cluster, registry, type, url); }
/** * doRefer方法建立一個RegistryDirectory實例,而後生成服務者消費者連接,並向註冊中心進行註冊. * 註冊完畢後,緊接着訂閱providers、configurators、routers 等節點下的數據.完成訂閱後, * RegistryDirectory會收到這幾個節點下的子節點信息.因爲一個服務可能部署在多臺服務器上, * 這樣就會在providers產生多個節點,這個時候就須要Cluster將多個服務節點合併爲一個, * 並生成一個Invoker. */ private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) { // 建立RegistryDirectory實例 RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url); // 設置註冊中心和協議 directory.setRegistry(registry); directory.setProtocol(protocol); // all attributes of REFER_KEY Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters()); // 生成服務消費者連接 URL subscribeUrl = new URL(Constants.CONSUMER_PROTOCOL, parameters.remove(Constants.REGISTER_IP_KEY), 0, type.getName(), parameters);
// 註冊服務消費者,在consumers目錄下新節點 if (!Constants.ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(Constants.REGISTER_KEY, true)) { registry.register( subscribeUrl.addParameters(Constants.CATEGORY_KEY, Constants.CONSUMERS_CATEGORY, Constants.CHECK_KEY, String.valueOf(false))); } // 訂閱providers、configurators、routers等節點數據 directory.subscribe(subscribeUrl.addParameter(Constants.CATEGORY_KEY, Constants.PROVIDERS_CATEGORY + "," + Constants.CONFIGURATORS_CATEGORY + "," + Constants.ROUTERS_CATEGORY)); // 一個註冊中心可能有多個服務提供者,所以這裏須要將多個服務提供者合併爲一個 Invoker invoker = cluster.join(directory); ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory); return invoker; }
// cluster.join(directory)該方法會走進MockClusterWrapper的join方法中 public class MockClusterWrapper implements Cluster { private Cluster cluster; public MockClusterWrapper(Cluster cluster) { this.cluster = cluster; } /** * 它是一個Wrapper類,對其餘如FailoverCluster包裝了一層 */ @Override public <T> Invoker<T> join(Directory<T> directory) throws RpcException { return new MockClusterInvoker<T>(directory, this.cluster.join(directory)); } }
public class FailoverCluster implements Cluster { public final static String NAME = "failover"; @Override public <T> Invoker<T> join(Directory<T> directory) throws RpcException { // 接着走到這裏,這裏就會建立FailoverClusterInvoker,接下去沒什麼關鍵邏輯,這裏就返回了一個Invoker return new FailoverClusterInvoker<T>(directory); } }
注意,最終返回的invoker是MockClusterInvoker服務器
// 一個註冊中心可能有多個服務提供者,所以這裏須要將多個服務提供者合併爲一個 Invoker invoker = cluster.join(directory);
// 生成代理類,核心 // Invoker建立完畢後,接下來要作的事情是爲服務接口生成代理對象.有了代理對象, // 便可進行遠程調用.代理對象生成的入口方法爲ProxyFactory的getProxy return (T) proxyFactory.getProxy(invoker);
// 先走到StubProxyFactoryWrapper的getProxy方法,它也是一個Wrapper public <T> T getProxy(Invoker<T> invoker) throws RpcException { T proxy = proxyFactory.getProxy(invoker); // 若是是非泛化 if (GenericService.class != invoker.getInterface()) { // 處理本地存根 String stub = invoker.getUrl().getParameter(Constants.STUB_KEY, invoker.getUrl().getParameter(Constants.LOCAL_KEY)); // 刪去處理本地存根代碼,不是本次分析重點 } return proxy; }
public abstract class AbstractProxyFactory implements ProxyFactory { // 接着走到AbstractProxyFactor的getProxy方法 @Override public <T> T getProxy(Invoker<T> invoker) throws RpcException { return getProxy(invoker, false); }
@Override public <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException { Class<?>[] interfaces = null; // 獲取接口列表 String config = invoker.getUrl().getParameter("interfaces"); if (config != null && config.length() > 0) { // 切分接口列表 String[] types = Constants.COMMA_SPLIT_PATTERN.split(config); if (types != null && types.length > 0) { interfaces = new Class<?>[types.length + 2]; // 設置服務接口類和EchoService.class到interfaces中 interfaces[0] = invoker.getInterface(); interfaces[1] = EchoService.class; for (int i = 0; i < types.length; i++) { // 加載接口類 interfaces[i + 1] = ReflectUtils.forName(types[i]); } } } if (interfaces == null) { interfaces = new Class<?>[]{invoker.getInterface(), EchoService.class}; }
// 爲http和hessian協議提供泛化調用支持 if (!invoker.getInterface().equals(GenericService.class) && generic) { int len = interfaces.length; Class<?>[] temp = interfaces; interfaces = new Class<?>[len + 1]; System.arraycopy(temp, 0, interfaces, 0, len); interfaces[len] = GenericService.class; } // 調用重載方法 return getProxy(invoker, interfaces); } public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types); }
public class JavassistProxyFactory extends AbstractProxyFactory { // 最終走到JavassistProxyFactory的getProxy方法 public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) { // 生成Proxy子類(Proxy是抽象類),並調用Proxy子類的newInstance方法建立Proxy實例 // 首先是經過Proxy的getProxy方法獲取Proxy子類,而後建立InvokerInvocationHandler // 對象,並將該對象傳給newInstance生成Proxy實例. InvokerInvocationHandler實現自 // JDK的InvocationHandler接口,具體的用途是攔截接口類調用 return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); } }
// 上述代碼分紅兩步,顯示Proxy.getProxy獲取Proxy子類 public static Proxy getProxy(Class<?>... ics) { // 調用重載方法 return getProxy(ClassHelper.getClassLoader(Proxy.class), ics); }
public static Proxy getProxy(ClassLoader cl, Class<?>... ics) { if (ics.length > 65535) throw new IllegalArgumentException("interface limit exceeded"); StringBuilder sb = new StringBuilder();
// 遍歷接口列表 for (int i = 0; i < ics.length; i++) { String itf = ics[i].getName(); // 檢測類型是否爲接口 if (!ics[i].isInterface()) throw new RuntimeException(itf + " is not a interface."); Class<?> tmp = null; try { // 從新加載接口類 tmp = Class.forName(itf, false, cl); } catch (ClassNotFoundException e) { } if (tmp != ics[i]) throw new IllegalArgumentException(ics[i] + " is not visible from class loader"); // 拼接接口全限定名,分隔符爲; sb.append(itf).append(';'); }
// 使用拼接後的接口名做爲key String key = sb.toString(); Map<String, Object> cache; synchronized (ProxyCacheMap) { cache = ProxyCacheMap.get(cl); if (cache == null) { cache = new HashMap<String, Object>(); ProxyCacheMap.put(cl, cache); } }
Proxy proxy = null; synchronized (cache) { do { // 從緩存中獲取Reference<Proxy>實例 Object value = cache.get(key); if (value instanceof Reference<?>) { proxy = (Proxy) ((Reference<?>) value).get(); if (proxy != null) return proxy; } // 併發控制,保證只有一個線程能夠進行後續操做 if (value == PendingGenerationMarker) { try { // 其餘線程在此處進行等待 cache.wait(); } } else { // 放置標誌位到緩存中,並跳出while循環進行後續操做 cache.put(key, PendingGenerationMarker); break; } } while (true); }
long id = PROXY_CLASS_COUNTER.getAndIncrement(); String pkg = null; ClassGenerator ccp = null, ccm = null; try { // 建立ClassGenerator對象 ccp = ClassGenerator.newInstance(cl); Set<String> worked = new HashSet<String>(); List<Method> methods = new ArrayList<Method>(); for (int i = 0; i < ics.length; i++) { // 檢測接口訪問級別是否爲protected或privete if (!Modifier.isPublic(ics[i].getModifiers())) { String npkg = ics[i].getPackage().getName(); if (pkg == null) { pkg = npkg; } else { if (!pkg.equals(npkg)) // 非public級別的接口必須在同一個包下,否者拋出異常 throw new IllegalArgumentException("xxx"); } }
// 添加接口到ClassGenerator中 ccp.addInterface(ics[i]); // 遍歷接口方法 for (Method method : ics[i].getMethods()) { // 獲取方法描述,可理解爲方法簽名 String desc = ReflectUtils.getDesc(method); // 若是方法描述字符串已在worked中,則忽略,考慮這種狀況, // A接口和B接口中包含一個徹底相同的方法 if (worked.contains(desc)) continue; worked.add(desc); int ix = methods.size(); // 獲取方法返回值類型和參數列表 Class<?> rt = method.getReturnType(); Class<?>[] pts = method.getParameterTypes(); // 生成 Object[] args = new Object[1...N] StringBuilder code = new StringBuilder("Object[] args = new Object[") .append(pts.length).append("];");
for (int j = 0; j < pts.length; j++) // 生成 args[1...N] = ($w)$1...N; code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";"); // 生成InvokerHandler接口的invoker方法調用語句,以下: // Object ret = handler.invoke(this, methods[1...N], args); code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);"); // 返回值不爲void if (!Void.TYPE.equals(rt)) // 生成返回語句,形如 return (java.lang.String) ret; code.append(" return ").append(asArgument(rt, "ret")).append(";"); methods.add(method); // 添加方法名、訪問控制符、參數列表、方法代碼等信息到ClassGenerator中 ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString()); } }
if (pkg == null) pkg = PACKAGE_NAME; // 構建接口代理類名稱: pkg + ".proxy" + id,好比org.apache.dubbo.proxy0 String pcn = pkg + ".proxy" + id; // 設置類名 ccp.setClassName(pcn); ccp.addField("public static java.lang.reflect.Method[] methods;"); // 生成 private java.lang.reflect.InvocationHandler handler; ccp.addField("private " + InvocationHandler.class.getName() + " handler;"); // 爲接口代理類添加帶有InvocationHandler參數的構造方法,好比: // porxy0(java.lang.reflect.InvocationHandler arg0) { // handler=$1; // } ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
// 爲接口代理類添加默認構造方法 ccp.addDefaultConstructor(); // 生成接口代理類 Class<?> clazz = ccp.toClass(); clazz.getField("methods").set(null, methods.toArray(new Method[0])); // 構建Proxy子類名稱,好比Proxy1,Proxy2等 String fcn = Proxy.class.getName() + id; ccm = ClassGenerator.newInstance(cl); ccm.setClassName(fcn); ccm.addDefaultConstructor(); ccm.setSuperClass(Proxy.class); // 爲Proxy的抽象方法newInstance生成實現代碼,形如: // public Object newInstance(java.lang.reflect.InvocationHandler h) { // return new org.apache.dubbo.proxy0($1); // } ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }"); // 生成Proxy實現類 Class<?> pc = ccm.toClass(); // 經過反射建立Proxy實例 proxy = (Proxy) pc.newInstance();
} catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } finally { // release ClassGenerator if (ccp != null) ccp.release(); if (ccm != null) ccm.release(); synchronized (cache) { if (proxy == null) cache.remove(key); else // 寫緩存 cache.put(key, new WeakReference<Proxy>(proxy)); // 喚醒其餘等待線程 cache.notifyAll(); } } return proxy; }
上面代碼比較複雜,咱們寫了大量的註釋。你們在閱讀這段代碼時,要搞清楚 ccp 和 ccm 的用途,否則會被搞暈。ccp 用於爲服務接口生成代理類,好比咱們有一個 DemoService 接口,這個接口代理類就是由 ccp 生成的。ccm 則是用於爲 org.apache.dubbo.common.bytecode.Proxy 抽象類生成子類,主要是實現 Proxy 類的抽象方法。生成的兩個類以下,你們能夠對照着看代碼會方便一些,如何獲取這兩個生成的類請參考 Dubbo中JavaAssist的Wrapper.getWrapper生成代理分析併發
public class Proxy0 extends Proxy implements ClassGenerator.DC { public Object newInstance(InvocationHandler invocationHandler) { return new proxy0(invocationHandler); } }
public class proxy0 implements ClassGenerator.DC, EchoService, DemoService { public static Method[] methods; private InvocationHandler handler; public String sayHello(String string) { Object[] arrobject = new Object[]{string}; // 經過proxy0中維護的handler就能夠實現調用 Object object = this.handler.invoke(this, methods[0], arrobject); return (String)object; } public Object $echo(Object object) { Object[] arrobject = new Object[]{object}; Object object2 = this.handler.invoke(this, methods[1], arrobject); return object2; } public proxy0() {} public proxy0(InvocationHandler invocationHandler) { this.handler = invocationHandler; } }
public class JavassistProxyFactory extends AbstractProxyFactory { public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) { // 如今已經分析完了第一步Proxy.getProxy // 接着分析第二步Proxy.newInstance() return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker)); } }
// Proxy.getProxy(interfaces)生成的是Proxy0實例對象,因此會走這裏的 // newInstance(InvocationHandler invocationHandler)方法 public class Proxy0 extends Proxy implements ClassGenerator.DC { public Object newInstance(InvocationHandler invocationHandler) { return new proxy0(invocationHandler); } }
public proxy0(InvocationHandler invocationHandler) { // 最終走到這裏並保存handler this.handler = invocationHandler; }
最終咱們的獲得的ref以下,和咱們分析的同樣,ref一個proxy0對象(注意和Proxy0區分,注意大小寫),裏面維護了一個InvokerInvocationHandler,它裏面維護了咱們以前建立好的MockClusterInvokerapp
// 建立代理類,核心 ref = createProxy(map);